diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag
index 20f11a528618c0e3a4b3f04b83fd4497e9c02694..c25ccdc6c9f36568ccf451af47c87157bdaed30e 100644
--- a/src/main/jastadd/Analysis.jrag
+++ b/src/main/jastadd/Analysis.jrag
@@ -131,6 +131,10 @@ aspect Constructors {
 }
 
 aspect Utils {
+
+  syn boolean RelationComponent.isMany() = false;
+  eq ManyRelationComponent.isMany() = true;
+
   public String SimpleTypeUse.toString() {
     return getID();
   }
diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd
index 59d8c53c1a0601580a234df1e94a46f66514c934..2a43b1154f180a0f277b3de06629de3e14cb4fb1 100644
--- a/src/main/jastadd/Backend.jadd
+++ b/src/main/jastadd/Backend.jadd
@@ -594,6 +594,18 @@ aspect NameResolutionHelper {
 
     sb.append("}\n\n");
 
+    sb.append("aspect ResolverTrigger {\n\n");
+
+    resolveAll(sb);
+
+    for (TypeDecl decl : getTypeDeclList()) {
+      if (!decl.isUnresolved()) {
+        decl.resolveAll(sb);
+      }
+    }
+
+    sb.append("}\n\n");
+
     sb.append("aspect RefResolverHelpers {\n\n");
 
     sb.append(ind(1) + "syn boolean ASTNode.unresolved() = false;\n");
@@ -679,6 +691,35 @@ aspect NameResolutionHelper {
       sb.append(ind(2) + "return resolve" + ofTypeDecl() + "(id);\n");
     sb.append(ind(1) + "}\n");
   }
+
+  public void Program.resolveAll(StringBuilder sb) {
+    sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n");
+    sb.append(ind(1) + "public void ASTNode.resolveAll() {\n");
+    sb.append(ind(1) + "}\n\n");
+
+    sb.append(ind(1) + "// enforce resolving in the entire subtree\n");
+    sb.append(ind(1) + "public void ASTNode.treeResolveAll() {\n");
+      sb.append(ind(2) + "if (children != null) {\n");
+        sb.append(ind(3) + "for (int i = 0; i < children.length; ++i) {\n");
+          sb.append(ind(4) + "ASTNode child = children[i];\n");
+          sb.append(ind(4) + "if (child != null) {\n");
+            sb.append(ind(5) + "child.treeResolveAll();\n");
+          sb.append(ind(4) + "}\n");
+        sb.append(ind(3) + "}\n");
+      sb.append(ind(2) + "}\n");
+      sb.append(ind(2) + "resolveAll();\n");
+    sb.append(ind(1) + "}\n");
+  }
+
+  public void TypeDecl.resolveAll(StringBuilder sb) {
+    sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n");
+    sb.append(ind(1) + "public void " + getID() + ".resolveAll() {\n");
+    for (RelationComponent relationComponent : relationComponents()) {
+      sb.append(ind(2) + "get" + relationComponent.nameCapitalized() + (relationComponent.isMany()?"List":"") + "();\n");
+    }
+      sb.append(ind(2) + "super.resolveAll();\n");
+    sb.append(ind(1) + "}\n");
+  }
 }
 
 aspect PrettyPrint {
diff --git a/src/test/java/org/jastadd/relast/tests/ResolveAll.java b/src/test/java/org/jastadd/relast/tests/ResolveAll.java
new file mode 100644
index 0000000000000000000000000000000000000000..3332f88c5ae919624486174b1c0e388ed0ab62f0
--- /dev/null
+++ b/src/test/java/org/jastadd/relast/tests/ResolveAll.java
@@ -0,0 +1,691 @@
+package org.jastadd.relast.tests;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import resolver.ast.A;
+import resolver.ast.B;
+import resolver.ast.Root;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import static org.jastadd.relast.tests.TestHelpers.readFile;
+import static org.junit.jupiter.api.Assertions.*;
+
+@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
+class ResolveAll {
+  private Root r;
+  private A a1;
+  private A a2;
+  private A a3;
+  private B b1;
+  private B b2;
+  private B b3;
+
+
+  @Test
+  void doubleRelastRun() throws IOException {
+
+    String firstRun = "./src/test/jastadd/relations/Relations.ast";
+    String secondRun = "./src/test/jastadd/relations/Relations2.ast";
+
+
+    String first = readFile(firstRun, Charset.defaultCharset());
+    String second = readFile(secondRun, Charset.defaultCharset());
+
+    Assertions.assertEquals(first, second);
+  }
+
+  /**
+   * rel A.Di1 -> B;
+   */
+  @Test
+  void testDi1() {
+    setup();
+    a1.setDi1(B.createRef("b2"));
+    a2.setDi1(B.createRef("b1"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    assertSame(a1.getDi1(), b2);
+    assertSame(a2.getDi1(), b1);
+
+    a2.setDi1(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertSame(a1.getDi1(), b2);
+    assertSame(a2.getDi1(), b2);
+
+    try {
+      a3.setDi1(null);
+      fail("should throw an exception");
+    } catch (Exception e) {
+      // OK
+    }
+  }
+
+
+  /**
+   * rel A.Di2? -> B;
+   */
+  @Test
+  void testDi2() {
+    setup();
+    a1.setDi2(B.createRef("b2"));
+    a2.setDi2(B.createRef("b1"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    assertSame(a1.getDi2(), b2);
+    assertSame(a2.getDi2(), b1);
+
+    a2.setDi2(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertSame(a1.getDi2(), b2);
+    assertSame(a2.getDi2(), b2);
+
+    a2.clearDi2();
+
+    assertSame(a1.getDi2(), b2);
+    assertNull(a2.getDi2());
+
+    assertTrue(a1.hasDi2());
+    assertFalse(a2.hasDi2());
+    assertFalse(a3.hasDi2());
+  }
+
+
+  /**
+   * rel A.Di3* -> B;
+   */
+  @Test
+  void testDi3() {
+    setup();
+    a1.addDi3(B.createRef("b1"));
+    a1.addDi3(B.createRef("b2"));
+    a1.addDi3(B.createRef("b3"));
+    a2.addDi3(B.createRef("b2"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+
+    assertEquals(a1.getDi3s(), Arrays.asList(b1, b2, b3));
+    assertEquals(a1.getDi3List(), Arrays.asList(b1, b2, b3));
+    assertEquals(a2.getDi3s(), Arrays.asList(b2));
+    assertEquals(a2.getDi3List(), Arrays.asList(b2));
+    assertEquals(a3.getDi3s(), Arrays.asList());
+    assertEquals(a3.getDi3List(), Arrays.asList());
+
+    a1.addDi3(B.createRef("b1"));
+    a2.addDi3(B.createRef("b1"));
+    a2.addDi3(B.createRef("b2"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    assertEquals(a1.getDi3s(), Arrays.asList(b1, b2, b3, b1));
+    assertEquals(a1.getDi3List(), Arrays.asList(b1, b2, b3, b1));
+    assertEquals(a2.getDi3s(), Arrays.asList(b2, b1, b2));
+    assertEquals(a2.getDi3List(), Arrays.asList(b2, b1, b2));
+    assertEquals(a3.getDi3s(), Arrays.asList());
+    assertEquals(a3.getDi3List(), Arrays.asList());
+
+    a1.removeDi3(b1);
+    a2.removeDi3(b2);
+    a1.resolveAll();
+    a2.resolveAll();
+
+    assertEquals(a1.getDi3s(), Arrays.asList(b2, b3, b1));
+    assertEquals(a1.getDi3List(), Arrays.asList(b2, b3, b1));
+    assertEquals(a2.getDi3s(), Arrays.asList(b1, b2));
+    assertEquals(a2.getDi3List(), Arrays.asList(b1, b2));
+    assertEquals(a3.getDi3s(), Arrays.asList());
+    assertEquals(a3.getDi3List(), Arrays.asList());
+  }
+
+
+  /**
+   * rel A.Bi1 <-> B.Bi1;
+   */
+
+
+  @Test
+  void testBi11() {
+    // Init
+    setup();
+    a1.setBi1(B.createRef("b1"));
+    a2.setBi1(B.createRef("b2"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    // Change
+    a2.setBi1(B.createRef("b1"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi1());
+    assertSame(a2.getBi1(), b1);
+    assertSame(b1.getBi1(), a2);
+    assertNull(b2.getBi1());
+  }
+
+  @Test
+  void testBi12() {
+    // Init
+    setup();
+    a1.setBi1(B.createRef("b2"));
+    a1.resolveAll();
+
+    // Change
+    a2.setBi1(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi1());
+    assertSame(a2.getBi1(), b2);
+    assertNull(b1.getBi1());
+    assertSame(b2.getBi1(), a2);
+  }
+
+
+  /**
+   * rel A.Bi2 <-> B.Bi2?;
+   */
+
+  @Test
+  void testBi21() {
+    // Init
+    setup();
+    a1.setBi2(B.createRef("b1"));
+    a2.setBi2(B.createRef("b2"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    // Change
+    a2.setBi2(B.createRef("b1"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi2());
+    assertSame(a2.getBi2(), b1);
+    assertSame(b1.getBi2(), a2);
+    assertNull(b2.getBi2());
+  }
+
+  @Test
+  void testBi22() {
+    // Init
+    setup();
+    a1.setBi2(B.createRef("b2"));
+    a1.resolveAll();
+
+    // Change
+    a2.setBi2(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi2());
+    assertSame(a2.getBi2(), b2);
+    assertNull(b1.getBi2());
+    assertSame(b2.getBi2(), a2);
+  }
+
+
+  /**
+   * rel A.Bi3 <-> B.Bi3*;
+   */
+  @Test
+  void testBi3() {
+    setup();
+    a2.setBi3(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi3());
+    assertSame(a2.getBi3(), b2);
+    assertEquals(b1.getBi3s(), Arrays.asList());
+    assertEquals(b1.getBi3List(), Arrays.asList());
+    assertEquals(b2.getBi3s(), Arrays.asList(a2));
+    assertEquals(b2.getBi3List(), Arrays.asList(a2));
+    assertEquals(b3.getBi3s(), Arrays.asList());
+    assertEquals(b3.getBi3List(), Arrays.asList());
+
+    a2.setBi3(B.createRef("b3"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi3());
+    assertSame(a2.getBi3(), b3);
+    assertEquals(b1.getBi3s(), Arrays.asList());
+    assertEquals(b1.getBi3List(), Arrays.asList());
+    assertEquals(b2.getBi3s(), Arrays.asList());
+    assertEquals(b2.getBi3List(), Arrays.asList());
+    assertEquals(b3.getBi3s(), Arrays.asList(a2));
+    assertEquals(b3.getBi3List(), Arrays.asList(a2));
+
+    a1.setBi3(B.createRef("b3"));
+    a3.setBi3(B.createRef("b3"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    assertSame(a1.getBi3(), b3);
+    assertSame(a2.getBi3(), b3);
+    assertSame(a3.getBi3(), b3);
+    assertEquals(b1.getBi3s(), Arrays.asList());
+    assertEquals(b1.getBi3List(), Arrays.asList());
+    assertEquals(b2.getBi3s(), Arrays.asList());
+    assertEquals(b2.getBi3List(), Arrays.asList());
+    assertEquals(b3.getBi3s(), Arrays.asList(a2, a1, a3));
+    assertEquals(b3.getBi3List(), Arrays.asList(a2, a1, a3));
+
+    a2.setBi3(B.createRef("b1"));
+    a2.resolveAll();
+
+    assertSame(a1.getBi3(), b3);
+    assertSame(a2.getBi3(), b1);
+    assertSame(a3.getBi3(), b3);
+    assertEquals(b1.getBi3s(), Arrays.asList(a2));
+    assertEquals(b1.getBi3List(), Arrays.asList(a2));
+    assertEquals(b2.getBi3s(), Arrays.asList());
+    assertEquals(b2.getBi3List(), Arrays.asList());
+    assertEquals(b3.getBi3s(), Arrays.asList(a1, a3));
+    assertEquals(b3.getBi3List(), Arrays.asList(a1, a3));
+
+    try {
+      a2.setBi3(null);
+      fail("should throw an exception");
+    } catch (Exception e) {
+      // OK
+    }
+  }
+
+
+  /**
+   * rel A.Bi4? <-> B.Bi4;
+   */
+  @Test
+  void testBi41() {
+    // Init
+    setup();
+    a1.setBi4(B.createRef("b1"));
+    a2.setBi4(B.createRef("b2"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    // Change
+    a2.setBi4(B.createRef("b1"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi4());
+    assertSame(a2.getBi4(), b1);
+    assertSame(b1.getBi4(), a2);
+    assertNull(b2.getBi4());
+  }
+
+  @Test
+  void testBi42() {
+    // Init
+    setup();
+    a1.setBi4(B.createRef("b2"));
+    a1.resolveAll();
+
+    // Change
+    a2.setBi4(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi4());
+    assertSame(a2.getBi4(), b2);
+    assertNull(b1.getBi4());
+    assertSame(b2.getBi4(), a2);
+  }
+
+
+  /**
+   * rel A.Bi5? <-> B.Bi5?;
+   */
+  @Test
+  void testBi51() {
+    // Init
+    setup();
+    a1.setBi5(B.createRef("b1"));
+    a2.setBi5(B.createRef("b2"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    // Change
+    a2.setBi5(B.createRef("b1"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi5());
+    assertSame(a2.getBi5(), b1);
+    assertSame(b1.getBi5(), a2);
+    assertNull(b2.getBi5());
+  }
+
+  @Test
+  void testBi52() {
+    // Init
+    setup();
+    a1.setBi5(B.createRef("b2"));
+    a1.resolveAll();
+
+    // Change
+    a2.setBi5(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi5());
+    assertSame(a2.getBi5(), b2);
+    assertNull(b1.getBi5());
+    assertSame(b2.getBi5(), a2);
+  }
+
+
+  /**
+   * rel A.Bi6? <-> B.Bi6*;
+   */
+  @Test
+  void testBi6() {
+    setup();
+    a2.setBi6(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi6());
+    assertSame(a2.getBi6(), b2);
+    assertEquals(b1.getBi6s(), Arrays.asList());
+    assertEquals(b1.getBi6List(), Arrays.asList());
+    assertEquals(b2.getBi6s(), Arrays.asList(a2));
+    assertEquals(b2.getBi6List(), Arrays.asList(a2));
+    assertEquals(b3.getBi6s(), Arrays.asList());
+    assertEquals(b3.getBi6List(), Arrays.asList());
+
+    a2.setBi6(B.createRef("b3"));
+    a2.resolveAll();
+
+    assertNull(a1.getBi6());
+    assertSame(a2.getBi6(), b3);
+    assertEquals(b1.getBi6s(), Arrays.asList());
+    assertEquals(b1.getBi6List(), Arrays.asList());
+    assertEquals(b2.getBi6s(), Arrays.asList());
+    assertEquals(b2.getBi6List(), Arrays.asList());
+    assertEquals(b3.getBi6s(), Arrays.asList(a2));
+    assertEquals(b3.getBi6List(), Arrays.asList(a2));
+
+    a1.setBi6(B.createRef("b3"));
+    a3.setBi6(B.createRef("b3"));
+    a1.resolveAll();
+    a2.resolveAll();
+
+    assertSame(a1.getBi6(), b3);
+    assertSame(a2.getBi6(), b3);
+    assertSame(a3.getBi6(), b3);
+    assertEquals(b1.getBi6s(), Arrays.asList());
+    assertEquals(b1.getBi6List(), Arrays.asList());
+    assertEquals(b2.getBi6s(), Arrays.asList());
+    assertEquals(b2.getBi6List(), Arrays.asList());
+    assertEquals(b3.getBi6s(), Arrays.asList(a2, a1, a3));
+    assertEquals(b3.getBi6List(), Arrays.asList(a2, a1, a3));
+
+    a2.setBi6(B.createRef("b1"));
+    a2.resolveAll();
+
+    assertSame(a1.getBi6(), b3);
+    assertSame(a2.getBi6(), b1);
+    assertSame(a3.getBi6(), b3);
+    assertEquals(b1.getBi6s(), Arrays.asList(a2));
+    assertEquals(b1.getBi6List(), Arrays.asList(a2));
+    assertEquals(b2.getBi6s(), Arrays.asList());
+    assertEquals(b2.getBi6List(), Arrays.asList());
+    assertEquals(b3.getBi6s(), Arrays.asList(a1, a3));
+    assertEquals(b3.getBi6List(), Arrays.asList(a1, a3));
+
+    a2.clearBi6();
+
+    assertSame(a1.getBi6(), b3);
+    assertNull(a2.getBi6());
+    assertSame(a3.getBi6(), b3);
+    assertEquals(b1.getBi6s(), Arrays.asList());
+    assertEquals(b1.getBi6List(), Arrays.asList());
+    assertEquals(b2.getBi6s(), Arrays.asList());
+    assertEquals(b2.getBi6List(), Arrays.asList());
+    assertEquals(b3.getBi6s(), Arrays.asList(a1, a3));
+    assertEquals(b3.getBi6List(), Arrays.asList(a1, a3));
+
+    assertTrue(a1.hasBi6());
+    assertFalse(a2.hasBi6());
+    assertTrue(a3.hasBi6());
+  }
+
+
+  /**
+   * rel A.Bi7* <-> B.Bi7;
+   */
+  @Test
+  void testBi7() {
+    setup();
+    a2.addBi7(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertEquals(a1.getBi7s(), Arrays.asList());
+    assertEquals(a1.getBi7List(), Arrays.asList());
+    assertEquals(a2.getBi7s(), Arrays.asList(b2));
+    assertEquals(a2.getBi7List(), Arrays.asList(b2));
+    assertNull(b1.getBi7());
+    assertSame(b2.getBi7(), a2);
+    assertNull(b3.getBi7());
+
+    a2.addBi7(B.createRef("b3"));
+    a1.addBi7(B.createRef("b2"));
+    a2.resolveAll();
+    a1.resolveAll();
+
+    assertEquals(a1.getBi7s(), Arrays.asList(b2));
+    assertEquals(a1.getBi7List(), Arrays.asList(b2));
+    assertEquals(a2.getBi7s(), Arrays.asList(b3));
+    assertEquals(a2.getBi7List(), Arrays.asList(b3));
+    assertNull(b1.getBi7());
+    assertSame(b2.getBi7(), a1);
+    assertSame(b3.getBi7(), a2);
+
+    a1.addBi7(B.createRef("b1"));
+    a1.resolveAll();
+
+    assertEquals(a1.getBi7s(), Arrays.asList(b2, b1));
+    assertEquals(a1.getBi7List(), Arrays.asList(b2, b1));
+    assertEquals(a2.getBi7s(), Arrays.asList(b3));
+    assertEquals(a2.getBi7List(), Arrays.asList(b3));
+    assertSame(b1.getBi7(), a1);
+    assertSame(b2.getBi7(), a1);
+    assertSame(b3.getBi7(), a2);
+
+    a1.addBi7(B.createRef("b1"));
+    a1.resolveAll();
+
+    assertEquals(a1.getBi7s(), Arrays.asList(b2, b1));
+    assertEquals(a1.getBi7List(), Arrays.asList(b2, b1));
+    assertEquals(a2.getBi7s(), Arrays.asList(b3));
+    assertEquals(a2.getBi7List(), Arrays.asList(b3));
+    assertSame(b1.getBi7(), a1);
+    assertSame(b2.getBi7(), a1);
+    assertSame(b3.getBi7(), a2);
+
+    a1.removeBi7(b1);
+
+    assertEquals(a1.getBi7s(), Arrays.asList(b2));
+    assertEquals(a1.getBi7List(), Arrays.asList(b2));
+    assertEquals(a2.getBi7s(), Arrays.asList(b3));
+    assertEquals(a2.getBi7List(), Arrays.asList(b3));
+    assertNull(b1.getBi7());
+    assertSame(b2.getBi7(), a1);
+    assertSame(b3.getBi7(), a2);
+  }
+
+
+  /**
+   * rel A.Bi8* <-> B.Bi8?;
+   */
+  @Test
+  void testBi8() {
+    setup();
+    a2.addBi8(B.createRef("b2"));
+    a2.resolveAll();
+
+    assertEquals(a1.getBi8s(), Arrays.asList());
+    assertEquals(a1.getBi8List(), Arrays.asList());
+    assertEquals(a2.getBi8s(), Arrays.asList(b2));
+    assertEquals(a2.getBi8List(), Arrays.asList(b2));
+    assertNull(b1.getBi8());
+    assertSame(b2.getBi8(), a2);
+    assertNull(b3.getBi8());
+
+    a2.addBi8(B.createRef("b3"));
+    a1.addBi8(B.createRef("b2"));
+    a2.resolveAll();
+    a1.resolveAll();
+
+    assertEquals(a1.getBi8s(), Arrays.asList(b2));
+    assertEquals(a1.getBi8List(), Arrays.asList(b2));
+    assertEquals(a2.getBi8s(), Arrays.asList(b3));
+    assertEquals(a2.getBi8List(), Arrays.asList(b3));
+    assertNull(b1.getBi8());
+    assertSame(b2.getBi8(), a1);
+    assertSame(b3.getBi8(), a2);
+
+    a1.addBi8(B.createRef("b1"));
+    a1.resolveAll();
+
+    assertEquals(a1.getBi8s(), Arrays.asList(b2, b1));
+    assertEquals(a1.getBi8List(), Arrays.asList(b2, b1));
+    assertEquals(a2.getBi8s(), Arrays.asList(b3));
+    assertEquals(a2.getBi8List(), Arrays.asList(b3));
+    assertSame(b1.getBi8(), a1);
+    assertSame(b2.getBi8(), a1);
+    assertSame(b3.getBi8(), a2);
+
+    a1.addBi8(B.createRef("b1"));
+    a1.resolveAll();
+
+    assertEquals(a1.getBi8s(), Arrays.asList(b2, b1));
+    assertEquals(a1.getBi8List(), Arrays.asList(b2, b1));
+    assertEquals(a2.getBi8s(), Arrays.asList(b3));
+    assertEquals(a2.getBi8List(), Arrays.asList(b3));
+    assertSame(b1.getBi8(), a1);
+    assertSame(b2.getBi8(), a1);
+    assertSame(b3.getBi8(), a2);
+
+    a1.removeBi8(b1);
+
+    assertEquals(a1.getBi8s(), Arrays.asList(b2));
+    assertEquals(a1.getBi8List(), Arrays.asList(b2));
+    assertEquals(a2.getBi8s(), Arrays.asList(b3));
+    assertEquals(a2.getBi8List(), Arrays.asList(b3));
+    assertNull(b1.getBi8());
+    assertSame(b2.getBi8(), a1);
+    assertSame(b3.getBi8(), a2);
+  }
+
+
+  /**
+   * rel A.Bi9* <-> B.Bi9*;
+   */
+  @Test
+  void testBi9() {
+    setup();
+    a1.addBi9(B.createRef("b1"));
+    a1.addBi9(B.createRef("b2"));
+    a1.resolveAll();
+
+    assertEquals(a1.getBi9s(), Arrays.asList(b1, b2));
+    assertEquals(a1.getBi9List(), Arrays.asList(b1, b2));
+    assertEquals(a2.getBi9s(), Arrays.asList());
+    assertEquals(a2.getBi9List(), Arrays.asList());
+    assertEquals(a3.getBi9s(), Arrays.asList());
+    assertEquals(a3.getBi9List(), Arrays.asList());
+    assertEquals(b1.getBi9s(), Arrays.asList(a1));
+    assertEquals(b1.getBi9List(), Arrays.asList(a1));
+    assertEquals(b2.getBi9s(), Arrays.asList(a1));
+    assertEquals(b2.getBi9List(), Arrays.asList(a1));
+    assertEquals(b3.getBi9s(), Arrays.asList());
+    assertEquals(b3.getBi9List(), Arrays.asList());
+
+    b3.addBi9(A.createRef("a1"));
+    b3.addBi9(A.createRef("a3"));
+    b3.addBi9(A.createRef("a1"));
+    b3.resolveAll();
+
+    assertEquals(a1.getBi9s(), Arrays.asList(b1, b2, b3, b3));
+    assertEquals(a1.getBi9List(), Arrays.asList(b1, b2, b3, b3));
+    assertEquals(a2.getBi9s(), Arrays.asList());
+    assertEquals(a2.getBi9List(), Arrays.asList());
+    assertEquals(a3.getBi9s(), Arrays.asList(b3));
+    assertEquals(a3.getBi9List(), Arrays.asList(b3));
+    assertEquals(b1.getBi9s(), Arrays.asList(a1));
+    assertEquals(b1.getBi9List(), Arrays.asList(a1));
+    assertEquals(b2.getBi9s(), Arrays.asList(a1));
+    assertEquals(b2.getBi9List(), Arrays.asList(a1));
+    assertEquals(b3.getBi9s(), Arrays.asList(a1, a3, a1));
+    assertEquals(b3.getBi9List(), Arrays.asList(a1, a3, a1));
+
+    b3.removeBi9(a1);
+
+    assertEquals(a1.getBi9s(), Arrays.asList(b1, b2, b3));
+    assertEquals(a1.getBi9List(), Arrays.asList(b1, b2, b3));
+    assertEquals(a2.getBi9s(), Arrays.asList());
+    assertEquals(a2.getBi9List(), Arrays.asList());
+    assertEquals(a3.getBi9s(), Arrays.asList(b3));
+    assertEquals(a3.getBi9List(), Arrays.asList(b3));
+    assertEquals(b1.getBi9s(), Arrays.asList(a1));
+    assertEquals(b1.getBi9List(), Arrays.asList(a1));
+    assertEquals(b2.getBi9s(), Arrays.asList(a1));
+    assertEquals(b2.getBi9List(), Arrays.asList(a1));
+    assertEquals(b3.getBi9s(), Arrays.asList(a3, a1));
+    assertEquals(b3.getBi9List(), Arrays.asList(a3, a1));
+  }
+
+
+  @Test
+  void testImmutableList() {
+    setup();
+
+    a1.addDi3(b1);
+    a1.addDi3(b2);
+    try {
+      a1.getDi3s().add(b3);
+      fail("should throw an exception");
+    } catch (Exception e) {
+      // OK
+    }
+
+    a1.addBi7(b1);
+    a1.addBi7(b2);
+    try {
+      a1.getBi7s().add(b3);
+      fail("should throw an exception");
+    } catch (Exception e) {
+      // OK
+    }
+
+    a1.addBi9(b1);
+    a1.addBi9(b2);
+    try {
+      a1.getBi9s().add(b3);
+      fail("should throw an exception");
+    } catch (Exception e) {
+      // OK
+    }
+  }
+
+  @BeforeEach
+  void setup() {
+    r = new Root();
+    a1 = new A("a1");
+    a2 = new A("a2");
+    a3 = new A("a3");
+    b1 = new B("b1");
+    b2 = new B("b2");
+    b3 = new B("b3");
+
+    r.addA(a1);
+    r.addA(a2);
+    r.addA(a3);
+    r.addB(b1);
+    r.addB(b2);
+    r.addB(b3);
+  }
+
+}