diff --git a/dumpAst/src/main/jastadd/DumpAst.relast b/dumpAst/src/main/jastadd/DumpAst.relast
index f1b76ce06860a121b868cdb47844d2fc33c70083..730a4245e198b562ba06b1591c91dfe73285a3b3 100644
--- a/dumpAst/src/main/jastadd/DumpAst.relast
+++ b/dumpAst/src/main/jastadd/DumpAst.relast
@@ -2,7 +2,7 @@ DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ;
 BuildConfig ::= <TypeIgnore> <TokenIgnore> <ChildIgnore> <AttributeIgnore> <RelationIgnore> <IncludeEmptyString:boolean> <Debug:boolean> ;
 PrintConfig ::= <Scale:double> <Version> Header* ;
 Header ::= <Value> ;
-DumpNode ::= <Name> <Label> <Object:Object> DumpChildNode* DumpToken* DumpRelation* ;
+DumpNode ::= <Name> <Label> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ;
 InnerDumpNode ;
 rel InnerDumpNode.DumpNode -> DumpNode ;
 
@@ -20,3 +20,6 @@ abstract DumpRelation ::= <Name> <Bidirectional:boolean> ;
 DumpNormalRelation : DumpRelation ;
 rel DumpNormalRelation.DumpNode -> DumpNode ;
 DumpListRelation : DumpRelation ::= InnerDumpNode* ;
+
+// type of NTA
+InvisiblePath ::= InnerDumpNode* ;
diff --git a/dumpAst/src/main/jastadd/Generation.jadd b/dumpAst/src/main/jastadd/Generation.jadd
index 06a8d254b133ff843108a6c02602b19167e1d282..38c7db06366d76ea4062b8a475e119966bff3388 100644
--- a/dumpAst/src/main/jastadd/Generation.jadd
+++ b/dumpAst/src/main/jastadd/Generation.jadd
@@ -54,6 +54,7 @@ import java.lang.String;aspect GenerationFrontend {
 
     /**
      * Exclude object with types matching at least one of the given regex strings.
+     * Exlcuding object won't be included in any output. However, their children are still processed.
      * @param regexes patterns to match type names
      * @return this
      * @see java.util.regex.Pattern#compile(java.lang.String)
@@ -166,16 +167,17 @@ aspect GenerationBackend {
     if (tti.transformed.containsKey(obj)) {
       return tti.transformed.get(obj);
     }
-    if (matches(getBuildConfig().typeIgnorePattern(), obj.getClass().getSimpleName())) {
-      tti.transformed.put(obj, null);
-      return null;
-    }
+//      tti.transformed.put(obj, null);
+//      return null;
     DumpNode node = new DumpNode();
     node.setObject(obj);
     node.setLabel(obj.getClass().getSimpleName() + "@" + obj.hashCode());
     node.setName("node" + tti.transformed.size());
     tti.transformed.put(obj, node);
     this.addDumpNode(node);
+    if (matches(getBuildConfig().typeIgnorePattern(), obj.getClass().getSimpleName())) {
+      node.setInvisible(true);
+    }
     if (node.isAstNode()) {
       // only caching node.analyseClass does not help, since we want to do this only once per class of a node
       final ClassAnalysisResult car;
@@ -370,6 +372,7 @@ aspect GenerationBackend {
     return (String) annotation.annotationType().getMethod("name").invoke(annotation);
   }
 
+  // --- isAstNode ---
   syn boolean DumpNode.isAstNode() {
     Class<?> clazz = getObject().getClass();
     for (java.lang.reflect.Constructor<?> constructor : clazz.getConstructors()) {
@@ -383,9 +386,34 @@ aspect GenerationBackend {
     return false;
   }
 
+  // --- astNodeAnnotationPrefix ---
   inh String DumpNode.astNodeAnnotationPrefix();
   eq DumpAst.getDumpNode().astNodeAnnotationPrefix() = getPackageName() + ".ASTNodeAnnotation";
 
+  // --- NTA: InvisiblePath ---
+  syn InvisiblePath DumpNode.getInvisiblePath() {
+    InvisiblePath result = new InvisiblePath();
+    for (DumpNode successor : reachableThroughInvisible()) {
+      result.addInnerDumpNode(new InnerDumpNode(successor));
+    }
+    return result;
+  }
+
+  // --- reachableThroughInvisible ---
+  syn java.util.List<DumpNode> DumpNode.reachableThroughInvisible() {
+    java.util.List<DumpNode> result = new java.util.ArrayList<>();
+    for (DumpChildNode childNode : getDumpChildNodeList()) {
+      for (DumpNode inner : childNode.innerNodes(false)) {
+        if (inner.getInvisible()) {
+          result.addAll(inner.reachableThroughInvisible());
+        } else if (this.getInvisible()) {
+          result.add(inner);
+        }
+      }
+    }
+    return result;
+  }
+
   class TransformationTransferInformation {
     java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>();
     java.util.Map<Class<?>, ClassAnalysisResult> classAnalysisResults = new java.util.HashMap<>();
diff --git a/dumpAst/src/main/jastadd/Navigation.jrag b/dumpAst/src/main/jastadd/Navigation.jrag
index a8adbd2246cb45d06fb74cf1f0ed8e260afc8f42..e03dbf37a0d9c7a615de6f7641fb730460b4199b 100644
--- a/dumpAst/src/main/jastadd/Navigation.jrag
+++ b/dumpAst/src/main/jastadd/Navigation.jrag
@@ -20,4 +20,50 @@ aspect Navigation {
   // --- printConfig ---
   inh PrintConfig BuildConfig.printConfig();
   eq DumpAst.getChild().printConfig() = getPrintConfig();
+
+  // --- containingDumpNode ---
+  inh DumpNode InnerDumpNode.containingDumpNode();
+  inh DumpNode DumpChildNode.containingDumpNode();
+  inh DumpNode DumpRelation.containingDumpNode();
+  eq DumpNode.getDumpChildNode().containingDumpNode() = this;
+  eq DumpNode.getDumpRelation().containingDumpNode() = this;
+  eq DumpNode.getInvisiblePath().containingDumpNode() = this;
+
+  // --- innerVisibleNodes ---
+  syn java.util.List<DumpNode> DumpChildNode.innerVisibleNodes() = innerNodes(true);
+  syn java.util.List<DumpNode> DumpRelation.innerVisibleNodes() = innerNodes(true);
+
+  // --- innerNodes ---
+  syn java.util.List<DumpNode> DumpChildNode.innerNodes(boolean onlyVisible);
+  eq DumpNormalChildNode.innerNodes(boolean onlyVisible) = onlyVisible && (containingDumpNode().getInvisible() || getDumpNode().getInvisible()) ?
+      java.util.Collections.emptyList() :
+      java.util.Collections.singletonList(getDumpNode());
+  eq DumpListChildNode.innerNodes(boolean onlyVisible) {
+    if (onlyVisible && containingDumpNode().getInvisible()) {
+      return java.util.Collections.emptyList();
+    }
+    java.util.List<DumpNode> result = new java.util.ArrayList<>();
+    getInnerDumpNodeList().forEach(inner -> {
+      if (!onlyVisible || !inner.getDumpNode().getInvisible()) {
+        result.add(inner.getDumpNode());
+      }
+    });
+    return result;
+  }
+  syn java.util.List<DumpNode> DumpRelation.innerNodes(boolean onlyVisible);
+  eq DumpNormalRelation.innerNodes(boolean onlyVisible) = onlyVisible && (containingDumpNode().getInvisible() || getDumpNode().getInvisible()) ?
+      java.util.Collections.emptyList() :
+      java.util.Collections.singletonList(getDumpNode());
+  eq DumpListRelation.innerNodes(boolean onlyVisible) {
+    if (onlyVisible && containingDumpNode().getInvisible()) {
+      return java.util.Collections.emptyList();
+    }
+    java.util.List<DumpNode> result = new java.util.ArrayList<>();
+    getInnerDumpNodeList().forEach(inner -> {
+      if (!onlyVisible || !inner.getDumpNode().getInvisible()) {
+        result.add(inner.getDumpNode());
+      }
+    });
+    return result;
+  }
 }
diff --git a/dumpAst/src/main/jastadd/Printing.jrag b/dumpAst/src/main/jastadd/Printing.jrag
index c41f02b1052560ba2bba70e84943d98a16f7c40b..a2ba999560eb4f412895b9236016581affd2647f 100644
--- a/dumpAst/src/main/jastadd/Printing.jrag
+++ b/dumpAst/src/main/jastadd/Printing.jrag
@@ -20,4 +20,9 @@ aspect Printing {
   syn String DumpRelation.label() = getName();
   syn String DumpToken.label() = getName();
   syn String DumpNode.label() = getLabel();
+
+  // --- bothVisible ---
+  syn boolean InnerDumpNode.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible();
+  syn boolean DumpNormalChildNode.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible();
+  syn boolean DumpNormalRelation.bothVisible() = !containingDumpNode().getInvisible() && !getDumpNode().getInvisible();
 }
diff --git a/dumpAst/src/main/resources/dumpAst.mustache b/dumpAst/src/main/resources/dumpAst.mustache
index 6b375b3706e4223af9143e095664265950d7ac2e..b8105eef93ba3054c4ff207abf38c233af8e0cb7 100644
--- a/dumpAst/src/main/resources/dumpAst.mustache
+++ b/dumpAst/src/main/resources/dumpAst.mustache
@@ -8,6 +8,7 @@ scale {{Scale}}
 
 {{#DumpNodes}}
 {{#isAstNode}}
+{{^Invisible}}
 object "{{label}}" as {{name}} {
 {{#DumpTokens}}
 {{#isDumpValueToken}}
@@ -15,35 +16,53 @@ object "{{label}}" as {{name}} {
 {{/isDumpValueToken}}
 {{/DumpTokens}}
 }
+{{/Invisible}}
 {{/isAstNode}}
 {{/DumpNodes}}
 
 {{#DumpNodes}}
 {{#DumpTokens}}
+{{^Invisible}}
 {{^isDumpValueToken}}
 {{outerNodeName}} ..> {{innerNodeName}} : {{label}}
 {{/isDumpValueToken}}
+{{/Invisible}}
 {{/DumpTokens}}
 {{#DumpChildNodes}}
 {{#isList}}
 {{#InnerDumpNodes}}
+{{#bothVisible}}
 {{outerNodeName}} *-- {{innerNodeName}} : {{label}}
+{{/bothVisible}}
 {{/InnerDumpNodes}}
 {{/isList}}
 {{^isList}}
+{{#bothVisible}}
 {{outerNodeName}} *-- {{innerNodeName}} : {{label}}
+{{/bothVisible}}
 {{/isList}}
 {{/DumpChildNodes}}
 {{#DumpRelations}}
 {{#isList}}
 {{#InnerDumpNodes}}
+{{#bothVisible}}
 {{outerNodeName}} {{#Bidirectional}}<{{/Bidirectional}}--> {{innerNodeName}} : {{label}}
+{{/bothVisible}}
 {{/InnerDumpNodes}}
 {{/isList}}
 {{^isList}}
+{{#bothVisible}}
 {{outerNodeName}} {{#Bidirectional}}<{{/Bidirectional}}--> {{innerNodeName}} : {{label}}
+{{/bothVisible}}
 {{/isList}}
 {{/DumpRelations}}
+{{^Invisible}}
+{{#InvisiblePath}}
+{{#InnerDumpNodes}}
+{{outerNodeName}} o.. {{innerNodeName}}
+{{/InnerDumpNodes}}
+{{/InvisiblePath}}
+{{/Invisible}}
 {{/DumpNodes}}
 {{#BuildConfig}}
 {{#Debug}}
diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java
index 16fc3b69aeda5496b62cfcb18f59540ad42c49e9..9e25685b089420f784648c8dddac2540f26722a2 100644
--- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java
+++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestExcluded.java
@@ -2,9 +2,13 @@ package de.tudresden.inf.st.jastadd.testDumper;
 
 import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpBuilder;
 import de.tudresden.inf.st.jastadd.dumpAst.ast.DumpNode;
+import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper;
+import org.jastadd.testDumper.ast.A;
 import org.jastadd.testDumper.ast.Root;
 import org.junit.jupiter.api.Test;
 
+import java.io.IOException;
+import java.nio.file.Paths;
 import java.util.List;
 
 import static de.tudresden.inf.st.jastadd.testDumper.TestUtils.*;
@@ -65,11 +69,11 @@ public class TestExcluded {
     Root root = setupTypes();
 
     List<DumpNode> nodes = TestUtils.dumpModel(root);
+    assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME);
     assertTypeDefaultMatches(nodes);
   }
 
   private void assertTypeDefaultMatches(List<DumpNode> nodes) {
-    assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME);
     // A
     assertThatMapOf(normalRelationChildren(findByName(nodes, A_NAME))).containsExactlyInAnyOrder(
         tuple("BiC1", C_NAME), tuple("BiC2", C_NAME), tuple("BiC3", C_NAME));
@@ -89,6 +93,7 @@ public class TestExcluded {
     Root root = setupTypes();
 
     List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("NonExistingType"));
+    assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME);
     assertTypeDefaultMatches(nodes);
   }
 
@@ -97,6 +102,7 @@ public class TestExcluded {
     Root root = setupTypes();
 
     List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("Nameable"));
+    assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(ROOT_NAME, A_NAME, B_NAME, C_NAME);
     assertTypeDefaultMatches(nodes);
   }
 
@@ -135,6 +141,44 @@ public class TestExcluded {
     assertThatMapOf(normalRelationChildren(findByName(nodes, B_NAME))).isEmpty();
   }
 
+  @Test
+  public void testTypesExcludeRegex() {
+    Root root = setupTypes();
+
+    List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("Ro*t"));
+    assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(A_NAME, B_NAME, C_NAME);
+    assertTypeDefaultMatches(nodes);
+  }
+
+  @Test
+  public void testTypesInvisiblePath() throws IOException {
+    final String A2_Name = "a2";
+    final String A3_Name = "a3";
+    final String C2_Name = "c2";
+    A mostInnerA = createA(A3_Name);
+    mostInnerA.setB(createB(B_NAME));
+    Root root = createRoot(createA(A_NAME,
+        createC(C_NAME,
+            createA(A2_Name,
+                createC(C2_Name, mostInnerA)))),
+        null);
+
+    List<DumpNode> nodes = TestUtils.dumpModel(root, db -> db.excludeTypes("A", "C"));
+    Dumper.read(root).excludeTypes("A", "C").dumpAsPNG(Paths.get("test.png"));
+    DumpNode actualRoot = findByName(nodes, ROOT_NAME);
+    assertThat(invisiblePath(actualRoot)).flatExtracting(NAME_EXTRACTOR).containsExactly(B_NAME);
+  }
+
+  @Test
+  public void testTokenDefault() {
+
+  }
+
+  @Test
+  public void testTokenExclude() {
+
+  }
+
   // --- copy from below here ---
 
   @Test
diff --git a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java
index f35e1cdfdbbcf7a5f6d990e51cfc0475386997f3..1398494b9b4a3be62f84196285641723f63b529a 100644
--- a/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java
+++ b/testDumper/src/test/java/de/tudresden/inf/st/jastadd/testDumper/TestUtils.java
@@ -14,7 +14,7 @@ import java.util.*;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
-import static org.assertj.core.api.Assertions.tuple;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 
 public class TestUtils {
   public static final Random rand = new Random();
@@ -50,6 +50,13 @@ public class TestUtils {
     return result;
   }
 
+  public static A createA(String name, C myC) {
+    A result = new A();
+    result.setName(name);
+    result.setMyC(myC);
+    return result;
+  }
+
   public static B createB(String name) {
     B result = new B();
     result.setName(name);
@@ -69,8 +76,15 @@ public class TestUtils {
     return result;
   }
 
-  public static final Function<DumpNode, String> NAME_EXTRACTOR = dp -> {
-    for (DumpToken dumpToken : dp.getDumpTokenList()) {
+  public static C createC(String name, A optA) {
+    C result = new C();
+    result.setName(name);
+    result.setA(optA);
+    return result;
+  }
+
+  public static final Function<DumpNode, String> NAME_EXTRACTOR = node -> {
+    for (DumpToken dumpToken : node.getDumpTokenList()) {
       if (dumpToken.getName().equals("Name")) {
         return dumpToken.asDumpValueToken().getValue().toString();
       }
@@ -99,9 +113,11 @@ public class TestUtils {
     ExposingDumpBuilder builder = new ExposingDumpBuilder(target);
     options.accept(builder);
     DumpAst dumpAst = builder.build();
+    // let mustache run, but ignore result
+    dumpAst.toPlantUml();
     List<DumpNode> result = new ArrayList<>();
     for (DumpNode dumpNode : dumpAst.getDumpNodeList()) {
-      if (dumpNode.isAstNode()) {
+      if (dumpNode.isAstNode() && !dumpNode.getInvisible()) {
         result.add(dumpNode);
       }
     }
@@ -124,7 +140,10 @@ public class TestUtils {
     for (DumpChildNode dumpChildNode : node.getDumpChildNodeList()) {
       if (!dumpChildNode.isList()) {
         // then it is a DumpNormalChildNode
-        result.put(dumpChildNode.label(), ((DumpNormalChildNode) dumpChildNode).getDumpNode());
+        DumpNode target = ((DumpNormalChildNode) dumpChildNode).getDumpNode();
+        if (!target.getInvisible()) {
+          result.put(dumpChildNode.label(), target);
+        }
       }
     }
     return result;
@@ -135,8 +154,11 @@ public class TestUtils {
     for (DumpChildNode dumpChildNode : node.getDumpChildNodeList()) {
       if (dumpChildNode.isList()) {
         // then it is a DumpListChildNode
-        ((DumpListChildNode) dumpChildNode).getInnerDumpNodeList().forEach(inner ->
-            result.computeIfAbsent(dumpChildNode.label(), key -> new ArrayList<>()).add(inner.getDumpNode()));
+        ((DumpListChildNode) dumpChildNode).getInnerDumpNodeList().forEach(inner -> {
+          if (!inner.getDumpNode().getInvisible()) {
+            result.computeIfAbsent(dumpChildNode.label(), key -> new ArrayList<>()).add(inner.getDumpNode());
+          }
+        });
       }
     }
     return result;
@@ -147,7 +169,10 @@ public class TestUtils {
     for (DumpRelation dumpRelation : node.getDumpRelationList()) {
       if (!dumpRelation.isList()) {
         // then it is a DumpNormalRelation
-        result.put(dumpRelation.label(), ((DumpNormalRelation) dumpRelation).getDumpNode());
+        DumpNode target = ((DumpNormalRelation) dumpRelation).getDumpNode();
+        if (!target.getInvisible()) {
+          result.put(dumpRelation.label(), target);
+        }
       }
     }
     return result;
@@ -158,8 +183,11 @@ public class TestUtils {
     for (DumpRelation dumpRelation : node.getDumpRelationList()) {
       if (dumpRelation.isList()) {
         // then it is a DumpListRelation
-        ((DumpListRelation) dumpRelation).getInnerDumpNodeList().forEach(
-            inner -> result.computeIfAbsent(dumpRelation.label(), key -> new ArrayList<>()).add(inner.getDumpNode()));
+        ((DumpListRelation) dumpRelation).getInnerDumpNodeList().forEach(inner -> {
+          if (!inner.getDumpNode().getInvisible()) {
+            result.computeIfAbsent(dumpRelation.label(), key -> new ArrayList<>()).add(inner.getDumpNode());
+          }
+        });
       }
     }
     return result;
@@ -170,7 +198,10 @@ public class TestUtils {
     for (DumpToken dumpToken : node.getDumpTokenList()) {
       if (!dumpToken.isDumpValueToken()) {
         // then it is a DumpReferenceToken
-        result.put(dumpToken.label(), ((DumpReferenceToken) dumpToken).getValue());
+        DumpNode target = ((DumpReferenceToken) dumpToken).getValue();
+        if (!target.getInvisible()) {
+          result.put(dumpToken.label(), target);
+        }
       }
     }
     return result;
@@ -188,6 +219,16 @@ public class TestUtils {
     return result;
   }
 
+  public static List<DumpNode> invisiblePath(DumpNode node) {
+    List<DumpNode> result = new ArrayList<>();
+    for (InnerDumpNode inner : node.getInvisiblePath().getInnerDumpNodeList()) {
+      DumpNode target = inner.getDumpNode();
+      assertFalse(target.getInvisible());
+      result.add(target);
+    }
+    return result;
+  }
+
   static class ExposingDumpBuilder extends DumpBuilder {
 
     protected ExposingDumpBuilder(Object target) {