diff --git a/src/jastadd/incremental/IncrementalDDG.jadd b/src/jastadd/incremental/IncrementalDDG.jadd
index 1470b385c6aafe42773569ca4789cf43a8143c26..86ef22b24c8891b0306a47e9093cf371e8d1f4e9 100644
--- a/src/jastadd/incremental/IncrementalDDG.jadd
+++ b/src/jastadd/incremental/IncrementalDDG.jadd
@@ -36,6 +36,25 @@ aspect IncrementalDDG {
     tt.expand("Grammar.emitDDGNode", out);
   }
 
+  /**
+   * Generate DDG cleanup methods,
+   *
+   * Methods: cleanupDependants, cleanupDependantsInTree
+   *
+   * After introducing single direction edges in the DDG flushed (emptied)
+   * dependants (or listeners) may remain in the DDG. The purpose of these
+   * methods is to clean up such dependants.
+   */
+  public void ASTDecl.genIncrementalCleanup(PrintWriter out) {
+    if (!config().incremental()) return;
+    TemplateContext tt = templateContext();
+    tt.bind("CleanupTokenDependants", genCleanupTokenDependantsString());
+    tt.bind("CleanupAttributeDependants", genCleanupAttributeDependantsString());
+    tt.expand("ASTDecl.cleanupDependantsMethod", out);
+    tt.bind("CleanupDependantsInNTAs", genCleanupDependantsInNTAsString());
+    tt.expand("ASTDecl.cleanupDependantsInTreeMethod", out);
+  }
+
   /**
    * Generate DDG nodes for storage that needs dependency tracking in an AST node.
    * The number of DDG nodes needed depend on the incremental configuration:
@@ -120,6 +139,57 @@ aspect IncrementalDDG {
     tt.expand("ASTDecl.incrementalCopyHandlerMethod", out);
   }
 
+  /**
+   * Generate string with code for cleaning up dependants in NTAs.
+   */
+  public String ASTDecl.genCleanupDependantsInNTAsString() {
+    StringBuffer res = new StringBuffer();
+    TemplateContext tt = templateContext();
+    for (AttrDecl attr : listOfCachedAttributes()) {
+      if ((attr.isNTA() || attr.getNTA()) && !attr.isPrimitive() &&
+         !(attr.type().equals("String") || attr.type().equals("java.lang.String"))) {
+        tt.bind("IsParameterized", attr.getNumParameter() > 0);
+        tt.bind("AttrSign", attr.signature());
+        res.append(tt.expand("ASTDecl.checkAndCleanupNTADependants"));
+      }
+    }
+    return res.toString();
+  }
+
+  /**
+   * Generate string with code for cleaning up dependants.
+   */
+  public String ASTDecl.genCleanupAttributeDependantsString() {
+    StringBuffer res = new StringBuffer();
+    TemplateContext tt = templateContext();
+    // Add dump string for each attribute
+    for (AttrDecl attr : listOfCachedAttributes()) {
+      tt.bind("IsParameterized", attr.getNumParameter() > 0);
+      tt.bind("IsNTA", (attr.isNTA() || attr.getNTA()) && !attr.isPrimitive() &&
+            !(attr.type().equals("String") || attr.type().equals("java.lang.String")));
+      tt.bind("AttrSign",  attr.signature());
+      res.append(tt.expand("ASTDecl.checkAndCleanupAttributeDependants"));
+    }
+    return res.toString();
+  }
+
+  /**
+   * Generate string with code for cleaning up token dependants.
+   */
+  public String ASTDecl.genCleanupTokenDependantsString() {
+    StringBuffer res = new StringBuffer();
+    TemplateContext tt = templateContext();
+    if (config().incrementalLevelParam() || config().incrementalLevelAttr()) {
+      for (Component c : components()) {
+        if (c instanceof TokenComponent && !c.isNTA()) {
+          tt.bind("Id",  ((TokenComponent)c).getTokenId().getID());
+          res.append(tt.expand("ASTDecl.checkAndCleanupTokenDependants"));
+        }
+      }
+    }
+    return res.toString();
+  }
+
   /**
    * Emit string for copying of token DDG nodes in a node.
    */
diff --git a/src/jastadd/incremental/IncrementalEval.jadd b/src/jastadd/incremental/IncrementalEval.jadd
index 53ad4e55f7c41213b26047c13138ba3f1c21d5a7..be4e8845476621c4e9d3b858281ca1a774d0aee8 100644
--- a/src/jastadd/incremental/IncrementalEval.jadd
+++ b/src/jastadd/incremental/IncrementalEval.jadd
@@ -48,6 +48,7 @@ aspect IncrementalEval {
     genIncrementalNotification(out);
     genIncrementalState(out);
     genIncrementalRegions(out);
+    genIncrementalCleanup(out);
     genIncrementalDebug(out);
   }
 
diff --git a/src/template/incremental/DDGNode.tt b/src/template/incremental/DDGNode.tt
index 94781fe1d5f5ce4491058e26e26e956f98eae356..e2d8fdd1a6fcde630c5e7e49353ad678dbba41d1 100644
--- a/src/template/incremental/DDGNode.tt
+++ b/src/template/incremental/DDGNode.tt
@@ -185,7 +185,6 @@ $endif
   // Dependency management
 
   public java.util.HashSet<$DDGNodeName> fListenerSet = new java.util.HashSet<$DDGNodeName>(4);
-  public java.util.HashSet<$DDGNodeName> fDependencySet = new java.util.HashSet<$DDGNodeName>(4);
 
   public boolean hasDependants() {
     return !fListenerSet.isEmpty();
@@ -193,33 +192,24 @@ $endif
 
   public void addDependant($DDGNodeName node) {
     fListenerSet.add(node);
-    node.addDependency(this);
   }
 
   public void removeDependant($DDGNodeName node) {
     fListenerSet.remove(node);
   }
 
-  public void clearDependants() {
-    for ($DDGNodeName node : fListenerSet) {
-      node.removeDependency(this);
-    }
-    fListenerSet.clear();
-  }
-
-  public void clearDependencies() {
-    for ($DDGNodeName node : fDependencySet) {
-      node.removeDependant(this);
+  public void cleanupDependants() {
+    java.util.Iterator<$DDGNodeName> itr = fListenerSet.iterator();
+    while (itr.hasNext()) {
+      $DDGNodeName node = itr.next();
+      if (node.isEmpty() || node.isGarbage()) {
+        itr.remove();
+      }
     }
-    fDependencySet.clear();
-  }
-
-  public void addDependency($DDGNodeName node) {
-    fDependencySet.add(node);
   }
 
-  public void removeDependency($DDGNodeName node) {
-    fDependencySet.remove(node);
+  public void clearDependants() {
+    fListenerSet.clear();
   }
 
   /*
@@ -233,26 +223,10 @@ $endif
         this.addDependant(l);
       }
     }
-    node.clearDependencies();
     node.clearDependants();
     node.throwAway();
   }
 
-  /*
-   * Transfers dependencies from another handler, used in rewrites.
-   */
-  public void transferDependenciesFrom($DDGNodeName node) {
-    if (node == null || this == node)
-      return;
-    for ($DDGNodeName l : node.fDependencySet) {
-      l.addDependant(this);
-    }
-$if (IncrementalPropLimit)
-    setCacheInDependent(node.cacheInDependent);
-$endif
-    node.clearDependencies();
-  }
-
   // Notification
 
   private boolean visited = false;
@@ -267,7 +241,6 @@ $endif
         if (!node.isGarbage()) {
           node.dependencyChanged();
         }
-        node.removeDependency(this);
       }
       visited = false;
     }
@@ -287,15 +260,7 @@ $if (IncrementalPropLimit)
       if (noCacheRead && !fNode.inc_valueAffected(fAttrID, fParams)) {
       } else {
 $endif
-        if (!fDependencySet.isEmpty()) {
-          // Remove dependencies
-          java.util.HashSet<$DDGNodeName> k = fDependencySet;
-          fDependencySet = new java.util.HashSet<$DDGNodeName>(4);
-          for ($DDGNodeName node : k) {
-            node.removeDependant(this);
-          }
-          fNode.reactToDependencyChange(fAttrID, fParams);
-        }
+        fNode.reactToDependencyChange(fAttrID, fParams);
 $if (IncrementalPropLimit)
       }
 $endif
@@ -361,6 +326,10 @@ $endif
     return fState == $ASTNode.inc_COMPUTED;
   }
 
+  public boolean isEmpty() {
+    return fState == $ASTNode.inc_EMPTY;
+  }
+
 $if (IncrementalDebug)
   // Debugging
 
@@ -555,3 +524,111 @@ $if (IncrementalLevelParam)
   getChild_handler = new $DDGNodeName[children.length];
 $endif
 ]]
+
+# Generate code for cleanup dependants method.
+ASTDecl.cleanupDependantsMethod = [[
+private boolean #name.inc_cleanupDependants_visited = false;
+public void #name.cleanupDependants() {
+  if (inc_cleanupDependants_visited) {
+    return;
+  }
+  inc_cleanupDependants_visited = true;
+$if (#isASTNodeDecl)
+$if (IncrementalLevelParam)
+  getParent_handler.cleanupDependants();
+  numChildren_handler.cleanupDependants();
+  for (int k = 0; getChild_handler != null && k < getChild_handler.length; k++) {
+    if (getChild_handler[k] != null) {
+      getChild_handler[k].cleanupDependants();
+    }
+  }
+$endif
+$endif
+$if (IncrementalLevelRegion)
+$if (IsRegionRoot)
+  handler.cleanupDependants();
+$endif
+$endif
+  $CleanupTokenDependants
+  $CleanupAttributeDependants
+$if (!#isASTNodeDecl)
+$if (IncrementalLevelRegion)
+$if (!IsRegionRoot)
+  super.cleanupDependants();
+$endif
+$else
+  super.cleanupDependants();
+$endif
+$endif
+  inc_cleanupDependants_visited = false;
+}
+]]
+
+# Generate code for checking token handler and cleaning up dependants.
+ASTDecl.checkAndCleanupTokenDependants = [[
+if (get$(Id)_handler != null) {
+  get$(Id)_handler.cleanupDependants();
+}
+]]
+
+# Generate code for checking attribute handler and cleaning up dependants.
+ASTDecl.checkAndCleanupAttributeDependants = [[
+$if (IncrementalLevelParam)
+$if (IsParameterized)
+for (java.util.Iterator itr = $(AttrSign)_handler.values().iterator(); itr.hasNext();) {
+  $DDGNodeName handler = ($DDGNodeName)itr.next();
+  handler.cleanupDependants();
+}
+$else
+if ($(AttrSign)_handler != null) {
+  $(AttrSign)_handler.cleanupDependants();
+}
+$endif
+$if (IsNTA)
+$if (IsParameterized)
+if ($(AttrSign)_proxy != null) {
+  $(AttrSign)_proxy.cleanupDependants();
+}
+$else
+if ($(AttrSign)_computed && ($(AttrSign)_value instanceof $ASTNode)) {
+  $(AttrSign)_value.cleanupDependants();
+}
+$endif
+$endif
+$endif
+]]
+
+# Generate code for method cleanupDependantsInTree.
+ASTDecl.cleanupDependantsInTreeMethod = [[
+private boolean #name.inc_cleanupDependantsInTree_visited = false;
+public void #name.cleanupDependantsInTree() {
+  if (inc_cleanupDependantsInTree_visited) {
+    return;
+  }
+  inc_cleanupDependantsInTree_visited = true;
+  cleanupDependants();
+  for (int i = 0; children != null && i < children.length; i++) {
+    $ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupDependantsInTree();
+  }
+  $CleanupDependantsInNTAs
+  inc_cleanupDependantsInTree_visited = false;
+}
+]]
+
+# Generate string with code for cleaning up dependants in NTAs.
+ASTDecl.checkAndCleanupNTADependants = [[
+$if (IsParameterized)
+if ($(AttrSign)_proxy != null) {
+  $(AttrSign)_proxy.cleanupDependantsInTree();
+}
+$else
+if ($(AttrSign)_computed && ($(AttrSign)_value instanceof $ASTNode)) {
+  $(AttrSign)_value.cleanupDependantsInTree();
+}
+$endif
+]]
+