diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index d96c5dbb48a2b644d9599ab3f407e9758393c714..48f1e58e5a61f8a77b0ba84eb93ba99a8c66427c 100644
--- a/src/main/jastadd/Analysis.jrag
+++ b/src/main/jastadd/Analysis.jrag
@@ -112,6 +112,12 @@ aspect ComponentAnalysis {
     }
     return set;
   }
+
+  syn boolean TypeDecl.needUnresolvedClass() {
+    // a TypeDecl needs an unresolved class, if it can appear in a relation
+    // TODO
+    return true;
+  }
 }
 
 aspect InstanceSupplier {
@@ -129,34 +135,23 @@ aspect InstanceSupplier {
     return subDecls;
   }
 
-  syn UnresolvedTypeDecl TypeDecl.instantiableUnresolved() {
+  syn TypeDecl TypeDecl.instantiableSubType() {
     if (getAbstract() == false) {
-      return this.getUnresolved();
+      return this;
     } else {
       for (TypeDecl sub : subTypeDecls()) {
         if (sub.getAbstract() == false) {
-          return sub.getUnresolved();
+          return sub;
         } else {
-          TypeDecl subInstance = sub.instantiableUnresolved();
+          TypeDecl subInstance = sub.instantiableSubType();
           if (subInstance != null) {
-            return subInstance.getUnresolved();
+            return subInstance;
           }
         }
       }
     }
     return null;
   }
-
-  syn UnresolvedTypeDecl TypeDecl.getUnresolved() {
-    java.util.List<TypeDecl> subDecls = new ArrayList();
-    for (TypeDecl decl : program().getTypeDeclList()) {
-      if (decl.isUnresolved() && decl.hasSuper() && decl.getSuper().getID().equals(getID())) {
-        return decl.asUnresolved();
-      }
-    }
-    // this should not happen
-    return null;
-  }
 }
 
 aspect Constructors {
diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd
index 5439024c5bc5245826d4856423e17b89b9fa26e1..528e4530ee0a14863ab1d56c2bb993c3a3a18f00 100644
--- a/src/main/jastadd/Backend.jadd
+++ b/src/main/jastadd/Backend.jadd
@@ -19,6 +19,47 @@ aspect BackendAbstractGrammar {
     }
   }
 
+  public void TypeDecl.generateUnresolvedClass(StringBuilder sb) {
+    if (getAbstract()) {
+      sb.append(ind(1) + "abstract ");
+    } else {
+      sb.append(ind(1));
+    }
+    sb.append("class " + "Unresolved$" + getID() + " extends " + getID() + "  implements Unresolved$Node {\n");
+
+    sb.append(ind(2) + "private String unresolved$Token;\n");
+    sb.append(ind(2) + "public String getUnresolved$Token() {\n");
+    sb.append(ind(3) + "return unresolved$Token;\n");
+    sb.append(ind(2) + "}\n");
+    sb.append(ind(2) + "void setUnresolved$Token(String token) {\n");
+    sb.append(ind(3) + "this.unresolved$Token = token;\n");
+    sb.append(ind(2) + "}\n");
+
+    sb.append(ind(2) + "private boolean unresolved$ResolveOpposite;\n");
+    sb.append(ind(2) + "public boolean getUnresolved$ResolveOpposite() {\n");
+    sb.append(ind(3) + "return unresolved$ResolveOpposite;\n");
+    sb.append(ind(2) + "}\n");
+    sb.append(ind(2) + "void setUnresolved$ResolveOpposite(boolean resolveOpposite) {\n");
+    sb.append(ind(3) + "this.unresolved$ResolveOpposite = resolveOpposite;\n");
+    sb.append(ind(2) + "}\n");
+
+    sb.append(ind(1) + "}\n");
+
+    sb.append(ind(1) + "Unresolved$Node " + getID() + ".as$Unresolved() {\n");
+    sb.append(ind(2) + "return null;\n");
+    sb.append(ind(1) + "}\n");
+    sb.append(ind(1) + "Unresolved$Node Unresolved$" + getID() + ".as$Unresolved() {\n");
+    sb.append(ind(2) + "return this;\n");
+    sb.append(ind(1) + "}\n");
+
+    sb.append(ind(1) + "boolean " + getID() + ".is$Unresolved() {\n");
+    sb.append(ind(2) + "return false;\n");
+    sb.append(ind(1) + "}\n");
+    sb.append(ind(1) + "boolean Unresolved$" + getID() + ".is$Unresolved() {\n");
+    sb.append(ind(2) + "return true;\n");
+    sb.append(ind(1) + "}\n");
+  }
+
   public void TypeDecl.generateAbstractGrammar(StringBuilder sb) {
     if (getAbstract()) {
       sb.append("abstract ");
@@ -212,9 +253,9 @@ aspect BackendDirectedAPI {
         sb.append(ind(3) + "boolean changed = false;\n");
         sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
           sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
-          sb.append(ind(4) + "if (element.unresolved()) {\n");
+          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
             sb.append(ind(5) + "changed = true;\n");
-            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.asUnresolved().get__token(), i);\n");
+            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
             sb.append(ind(5) + "l.set(i, resolvedElement);\n");
           sb.append(ind(4) + "}\n");
         sb.append(ind(3) + "}\n");
@@ -279,11 +320,11 @@ aspect BackendDirectedAPI {
     }
     sb.append("() {\n");
     if (resolverHelper | serializer) {
-      sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null && get" + getImplAttributeName() + "().unresolved()) {\n");
-        sb.append(ind(3) + "if (get" + getImplAttributeName() + "().asUnresolved().get__resolve_opposite()) {\n");
-          sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(get" + getImplAttributeName() + "().asUnresolved().get__token()));\n");
+      sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null && get" + getImplAttributeName() + "().is$Unresolved()) {\n");
+        sb.append(ind(3) + "if (get" + getImplAttributeName() + "().as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
+          sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(get" + getImplAttributeName() + "().as$Unresolved().getUnresolved$Token()));\n");
         sb.append(ind(3) + "} else {\n");
-          sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(get" + getImplAttributeName() + "().asUnresolved().get__token()));\n");
+          sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(get" + getImplAttributeName() + "().as$Unresolved().getUnresolved$Token()));\n");
         sb.append(ind(3) + "}\n");
       sb.append(ind(2) + "}\n");
     }
@@ -368,7 +409,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(3) + "get" + getImplAttributeName() + "().set" + otherSide().getImplAttributeName() + "(null);\n");
     sb.append(ind(2) + "}\n");
     if (resolverHelper | serializer) {
-      sb.append(ind(2) + "if (o != null && !o.unresolved() && o.get" + otherSide().getImplAttributeName() + "() != null) {\n");
+      sb.append(ind(2) + "if (o != null && !o.is$Unresolved() && o.get" + otherSide().getImplAttributeName() + "() != null) {\n");
     } else {
       sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n");
     }
@@ -376,7 +417,7 @@ aspect BackendBidirectionalAPI {
     sb.append(ind(2) + "}\n");
     sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");
     if (resolverHelper | serializer) {
-      sb.append(ind(2) + "if (o == null || !o.unresolved()) {\n");
+      sb.append(ind(2) + "if (o == null || !o.is$Unresolved()) {\n");
       if (isOpt) {
         sb.append(ind(3) + "if (o != null) {\n");
         sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
@@ -425,10 +466,10 @@ aspect BackendBidirectionalAPI {
         sb.append(ind(3) + "boolean changed = false;\n");
         sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
           sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
-          sb.append(ind(4) + "if (element.unresolved()) {\n");
+          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
             sb.append(ind(5) + "changed = true;\n");
-            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.asUnresolved().get__token(), i);\n");
-            sb.append(ind(5) + "if (resolvedElement != null && element.asUnresolved().get__resolve_opposite()) {\n");
+            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
+            sb.append(ind(5) + "if (resolvedElement != null && element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
               sb.append(ind(6) + ASTNode.listClass + "<" + toTypeDecl() + "> otherList = resolvedElement.get" + opposite.getImplAttributeName() + "();\n");
               sb.append(ind(6) + "if (otherList == null) {\n");
                 sb.append(ind(7) + "otherList = new " + listClass + "<>();\n");
@@ -532,10 +573,10 @@ aspect BackendBidirectionalAPI {
         sb.append(ind(3) + "boolean changed = false;\n");
         sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
           sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
-          sb.append(ind(4) + "if (element.unresolved()) {\n");
+          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
             sb.append(ind(5) + "changed = true;\n");
-            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.asUnresolved().get__token(), i);\n");
-            sb.append(ind(5) + "if (element.asUnresolved().get__resolve_opposite()) {\n");
+            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
+            sb.append(ind(5) + "if (element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
               sb.append(ind(6) + toTypeDecl() + " oldTarget = resolvedElement.get" + opposite.getImplAttributeName() + "();\n");
               sb.append(ind(6) + "if (oldTarget != null && oldTarget != this) {\n");
                 sb.append(ind(7) + "oldTarget.get" + getImplAttributeName() + "().remove(resolvedElement);\n");
@@ -745,12 +786,6 @@ aspect LowerBoundCheck {
 
 aspect NameResolutionHelper {
 
-  syn boolean TypeDecl.isUnresolved() = false;
-  eq UnresolvedTypeDecl.isUnresolved() = true;
-
-  syn UnresolvedTypeDecl TypeDecl.asUnresolved() = null;
-  eq UnresolvedTypeDecl.asUnresolved() = this;
-
   public String Program.generateRewriteToSuperTypeStub() {
     StringBuilder sb = new StringBuilder();
     generateRewriteToSuperTypeStub(sb);
@@ -771,10 +806,8 @@ aspect NameResolutionHelper {
     }
 
     for (TypeDecl decl : getTypeDeclList()) {
-      if (decl.isUnresolved()) {
-        decl.asUnresolved().generateContextIndependentNameResolution(sb);
-        sb.append("\n");
-      }
+      decl.generateContextIndependentNameResolution(sb);
+      sb.append("\n");
     }
     sb.append("}\n\n");
   }
@@ -784,9 +817,7 @@ aspect NameResolutionHelper {
     sb.append("aspect ReferenceCreation {\n\n");
 
     for (TypeDecl decl : getTypeDeclList()) {
-      if (decl.isUnresolved()) {
-        decl.asUnresolved().createReferenceCreator(sb);
-      }
+      decl.createReferenceCreator(sb);
     }
 
     sb.append("}\n\n");
@@ -796,78 +827,58 @@ aspect NameResolutionHelper {
     resolveAll(sb);
 
     for (TypeDecl decl : getTypeDeclList()) {
-      if (!decl.isUnresolved()) {
-        decl.resolveAll(sb);
-      }
+      decl.resolveAll(sb);
     }
 
     sb.append("}\n\n");
 
     sb.append("aspect RefResolverHelpers {\n\n");
 
-    sb.append(ind(1) + "public interface __Unresolved {\n");
-    sb.append(ind(2) + "abstract String get__token();\n");
-    sb.append(ind(2) + "abstract boolean get__resolve_opposite();\n");
+    sb.append(ind(1) + "interface Unresolved$Node {\n");
+    sb.append(ind(2) + "String getUnresolved$Token();\n");
+    sb.append(ind(2) + "boolean getUnresolved$ResolveOpposite();\n");
     sb.append(ind(1) + "}\n\n");
 
-    for (TypeDecl decl : getTypeDeclList()) {
-      if (decl.isUnresolved()) {
-        sb.append(ind(1) + decl.getID() + " implements __Unresolved;\n");
-      }
-    }
-
-    sb.append(ind(1) + "syn boolean ASTNode.unresolved() = false;\n");
-    for (TypeDecl decl : getTypeDeclList()) {
-      if (decl.isUnresolved()) {
-        sb.append(ind(1) + "eq " + decl.getID() + ".unresolved() = true;\n");
-      }
-    }
-    sb.append("\n");
-    sb.append(ind(1) + "syn __Unresolved ASTNode.asUnresolved() = null;\n");
-    for (TypeDecl decl : getTypeDeclList()) {
-      if (decl.isUnresolved()) {
-        sb.append(ind(1) + "eq " + decl.getID() + ".asUnresolved() = this;\n");
+    for (TypeDecl td: getTypeDecls()) {
+      if (td.needUnresolvedClass()) {
+        td.generateUnresolvedClass(sb);
       }
     }
 
     sb.append("\n}\n");
   }
 
-  public void UnresolvedTypeDecl.createReferenceCreator(StringBuilder sb) {
-
-    String superType = this.getSuper().getID();
+  public void TypeDecl.createReferenceCreator(StringBuilder sb) {
 
-    TypeDecl instantiableUnresolved = this.getSuper().decl().instantiableUnresolved();
-    if (instantiableUnresolved == null) {
-      System.out.println(getID());
+    TypeDecl instantiableSubType = instantiableSubType();
+    if (instantiableSubType == null) {
+      throw new RuntimeException("unable to find instantiable subtype for " + getID());
     }
 
-    sb.append(ind(1) + "public static " + superType + " " + superType + ".createRef(String ref) {\n");
-      sb.append(ind(2) + instantiableUnresolved.getID() + " unresolvedNode = new " + instantiableUnresolved.getID() + "();\n");
-      sb.append(ind(2) + "unresolvedNode.set__token(ref);\n");
-      sb.append(ind(2) + "unresolvedNode.set__resolve_opposite(true);\n");
+    sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRef(String ref) {\n");
+      sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n");
+      sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n");
+      sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(true);\n");
       sb.append(ind(2) + "return unresolvedNode;\n");
     sb.append(ind(1) + "}\n");
 
-    sb.append(ind(1) + "public static " + superType + " " + superType + ".createRefDirection(String ref) {\n");
-      sb.append(ind(2) + instantiableUnresolved.getID() + " unresolvedNode = new " + instantiableUnresolved.getID() + "();\n");
-      sb.append(ind(2) + "unresolvedNode.set__token(ref);\n");
-      sb.append(ind(2) + "unresolvedNode.set__resolve_opposite(false);\n");
+    sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRefDirection(String ref) {\n");
+      sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n");
+      sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n");
+      sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(false);\n");
       sb.append(ind(2) + "return unresolvedNode;\n");
     sb.append(ind(1) + "}\n");
   }
 
-  public void UnresolvedTypeDecl.generateContextIndependentNameResolution(StringBuilder sb) {
-
-    String superType = this.getSuper().getID();
+  public void TypeDecl.generateContextIndependentNameResolution(StringBuilder sb) {
 
     sb.append(ind(1) + "// context-independent name resolution\n");
-    sb.append(ind(1) + "syn " + superType + " ASTNode.globallyResolve" + superType + "ByToken(String id) {\n");
+    sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n");
     if (serializer) {
-      sb.append(ind(2) + "return (" + superType + ") globallyResolveASTNodeByUID(id);\n");
+      sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n");
     } else {
       sb.append(ind(2) + "// perform context independent name resolution here using the id\n");
-      sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + superType + " not implemented.\");\n");
+      sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + getID() + " not implemented.\");\n");
     }
     sb.append(ind(1) + "}\n");
   }
@@ -1006,9 +1017,7 @@ aspect Serializer {
     sb.append(ind(1) + "}\n");
 
     for (TypeDecl decl : getTypeDeclList()) {
-      if (!decl.isUnresolved()) {
-        decl.deserialize(sb);
-      }
+      decl.deserialize(sb);
     }
 
     sb.append("}\n");
@@ -1027,9 +1036,7 @@ aspect Serializer {
     sb.append(ind(1) + "}\n");
 
     for (TypeDecl decl : getTypeDeclList()) {
-      if (!decl.isUnresolved()) {
-        decl.serialize(sb);
-      }
+      decl.serialize(sb);
     }
 
     sb.append("}\n");
diff --git a/src/main/jastadd/RelAst.ast b/src/main/jastadd/RelAst.ast
index 5098ece3a779a7919dcf4af2ed6ce93cb5c40e6f..3a17c0cfb7fea19f5b33dc9a9bb8fe613137b12b 100644
--- a/src/main/jastadd/RelAst.ast
+++ b/src/main/jastadd/RelAst.ast
@@ -1,6 +1,5 @@
 Program ::= TypeDecl* Relation*;
 TypeDecl ::= <ID> <Abstract:boolean> [Super:TypeUse] Component*;
-UnresolvedTypeDecl:TypeDecl;
 
 abstract Component ::= <ID>;
 abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse;
diff --git a/src/main/java/org/jastadd/relast/compiler/Compiler.java b/src/main/java/org/jastadd/relast/compiler/Compiler.java
index 93afb42b34eba9a1718af25658ecd2a414916d00..9100db9979018bc31be81308ee4c1d8214b3c6d5 100644
--- a/src/main/java/org/jastadd/relast/compiler/Compiler.java
+++ b/src/main/java/org/jastadd/relast/compiler/Compiler.java
@@ -36,7 +36,6 @@ public class Compiler {
     }
 
     List<String> filenames = commandLine.getArguments();
-    List<TypeDecl> unresolvedDecls = new ArrayList<>();
     Program p = parseProgram(filenames);
 
     if (optionJastAddList.isSet()) {
@@ -51,18 +50,6 @@ public class Compiler {
       for (TypeDecl typeDecl : p.getTypeDecls()) {
         nonTerminals.add(typeDecl);
       }
-
-      // add a new typeDecl with a prefix "Unresolved"
-      for (TypeDecl typeDecl : nonTerminals) {
-        UnresolvedTypeDecl unresolvedDecl = new UnresolvedTypeDecl();
-        unresolvedDecl.setID("__unresolved" + typeDecl.getID());
-        unresolvedDecl.setAbstract(typeDecl.getAbstract());
-        unresolvedDecl.setSuper(new SimpleTypeUse(typeDecl.getID()));
-        unresolvedDecl.addComponent(new TokenComponent("__token", new SimpleTypeUse("String")));
-        unresolvedDecl.addComponent(new TokenComponent("__resolve_opposite", new SimpleTypeUse("boolean")));
-        p.addTypeDecl(unresolvedDecl);
-        unresolvedDecls.add(unresolvedDecl);
-      }
     }
 
     if (!p.errors().isEmpty()) {