Fix diff, conflict detection and merging of non-unique attributes

Non-unique multi-valued attributes had been completely ignored during
the conception of EMF Compare and thus every step of the process was
failing.

Change-Id: I09c7ff8cf3eee5fff6c76128a3142a29acb15987
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java
index 13879b3..4332710 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java
@@ -286,14 +286,14 @@
 		childNode = node.getChildren().get(0);
 		checkText(childNode, "Periodical -> Item [eClassifiers delete]");
 		assertEquals(0, childNode.getChildren().size());
-		// eSuperTypes add
-		childNode = node.getChildren().get(1);
-		checkText(childNode, "TitledItem [eSuperTypes add]");
-		assertEquals(0, childNode.getChildren().size());
 		// eSuperTypes delete
-		childNode = node.getChildren().get(2);
+		childNode = node.getChildren().get(1);
 		checkText(childNode, "Item [eSuperTypes delete]");
 		assertEquals(0, childNode.getChildren().size());
+		// eSuperTypes add
+		childNode = node.getChildren().get(2);
+		checkText(childNode, "TitledItem [eSuperTypes add]");
+		assertEquals(0, childNode.getChildren().size());
 
 		// Periodical.issuesPerYear
 		childNode = node.getChildren().get(3);
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java
index 2a4c89d..0ac3222 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java
@@ -273,13 +273,13 @@
 		checkNoChild(node0);
 		assertNotNull(((Diff)node0.getData()).getConflict());
 		TreeNode node1 = periodicalChildren.get(1);
-		checkRefChange(node1, RIGHT, ADD, "eSuperTypes");
+		checkRefChange(node1, LEFT, DELETE, "eSuperTypes");
 		checkNoChild(node1);
-		assertNotNull(((Diff)node1.getData()).getConflict());
-		assertSame(((Diff)node0.getData()).getConflict(), ((Diff)node1.getData()).getConflict());
 		TreeNode node2 = periodicalChildren.get(2);
-		checkRefChange(node2, LEFT, DELETE, "eSuperTypes");
+		checkRefChange(node2, RIGHT, ADD, "eSuperTypes");
 		checkNoChild(node2);
+		assertNotNull(((Diff)node2.getData()).getConflict());
+		assertSame(((Diff)node0.getData()).getConflict(), ((Diff)node2.getData()).getConflict());
 
 		TreeNode node3 = periodicalChildren.get(3);
 		assertTrue(node3 instanceof MatchNode);
diff --git a/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore b/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
index d85c30e..64d4796 100644
--- a/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
+++ b/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
@@ -26,6 +26,10 @@
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="multiValuedAttribute" upperBound="-1"
         eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
   </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="NodeMultiValuedNonUniqueAttribute" eSuperTypes="#//Node">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="multiValuedAttribute" unique="false"
+        upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+  </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="NodeSingleValueReference" eSuperTypes="#//Node">
     <eStructuralFeatures xsi:type="ecore:EReference" name="singleValuedReference"
         eType="#//Node"/>
diff --git a/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel b/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
index fac0cb1..3fc6d78 100644
--- a/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
+++ b/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
@@ -8,6 +8,11 @@
   <genPackages prefix="Nodes" basePackage="org.eclipse.emf.compare.tests" resource="XMI"
       disposableProviderFactory="true" contentTypeIdentifier="org.eclipse.emf.compare.test.nodes.contenttype"
       ecorePackage="nodes.ecore#/">
+    <genEnums typeSafeEnumCompatible="false" ecoreEnum="nodes.ecore#//NodeEnum">
+      <genEnumLiterals ecoreEnumLiteral="nodes.ecore#//NodeEnum/A"/>
+      <genEnumLiterals ecoreEnumLiteral="nodes.ecore#//NodeEnum/B"/>
+      <genEnumLiterals ecoreEnumLiteral="nodes.ecore#//NodeEnum/C"/>
+    </genEnums>
     <genClasses ecoreClass="nodes.ecore#//Node">
       <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//Node/name"/>
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference nodes.ecore#//Node/containmentRef1"/>
@@ -25,6 +30,9 @@
     <genClasses ecoreClass="nodes.ecore#//NodeMultiValuedAttribute">
       <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeMultiValuedAttribute/multiValuedAttribute"/>
     </genClasses>
+    <genClasses ecoreClass="nodes.ecore#//NodeMultiValuedNonUniqueAttribute">
+      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeMultiValuedNonUniqueAttribute/multiValuedAttribute"/>
+    </genClasses>
     <genClasses ecoreClass="nodes.ecore#//NodeSingleValueReference">
       <genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeSingleValueReference/singleValuedReference"/>
     </genClasses>
@@ -58,5 +66,11 @@
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeFeatureMapContainment2/multiple"/>
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeFeatureMapContainment2/single"/>
     </genClasses>
+    <genClasses ecoreClass="nodes.ecore#//NodeSingleValueEEnumAttribute">
+      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeSingleValueEEnumAttribute/singlevalueEEnumAttribute"/>
+    </genClasses>
+    <genClasses ecoreClass="nodes.ecore#//NodeMultiValueEEnumAttribute">
+      <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeMultiValueEEnumAttribute/multiValueEEnumAttribute"/>
+    </genClasses>
   </genPackages>
 </genmodel:GenModel>
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java
index 8b9626a..4de8697 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java
@@ -20,11 +20,11 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.Node#getName <em>Name</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.Node#getContainmentRef1 <em>Containment Ref1</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNode()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java
index 836029f..d5d3213 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java
@@ -133,6 +133,8 @@
 	 * Returns the '<em><b>Node Enum</b></em>' literal with the specified literal value.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
+	 * @param literal the literal.
+	 * @return the matching enumerator or <code>null</code>.
 	 * @generated
 	 */
 	public static NodeEnum get(String literal) {
@@ -149,6 +151,8 @@
 	 * Returns the '<em><b>Node Enum</b></em>' literal with the specified name.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
+	 * @param name the name.
+	 * @return the matching enumerator or <code>null</code>.
 	 * @generated
 	 */
 	public static NodeEnum getByName(String name) {
@@ -165,6 +169,8 @@
 	 * Returns the '<em><b>Node Enum</b></em>' literal with the specified integer value.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
+	 * @param value the integer value.
+	 * @return the matching enumerator or <code>null</code>.
 	 * @generated
 	 */
 	public static NodeEnum get(int value) {
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java
index 20e5621..799b1c4 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java
@@ -20,12 +20,12 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment#getMap <em>Map</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment#getFirstKey <em>First Key</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment#getSecondKey <em>Second Key</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeFeatureMapContainment()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java
index 2652375..cb0b073 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java
@@ -19,12 +19,12 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment2#getMap2 <em>Map2</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment2#getMultiple <em>Multiple</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment2#getSingle <em>Single</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeFeatureMapContainment2()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java
index 68d0395..e879c10 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java
@@ -20,12 +20,12 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment#getMapNC <em>Map NC</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment#getFirstKeyNC <em>First Key NC</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment#getSecondKeyNC <em>Second Key NC</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeFeatureMapNonContainment()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java
index 1b39939..6523f67 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java
@@ -19,10 +19,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValueEEnumAttribute#getMultiValueEEnumAttribute <em>Multi Value EEnum Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValueEEnumAttribute()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java
index 57d33c5..35f4092 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java
@@ -19,10 +19,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValueReference#getMultiValuedReference <em>Multi Valued Reference</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValueReference()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java
index 4a7eec1..7d14d9f 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java
@@ -19,10 +19,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedAttribute#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValuedAttribute()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java
new file mode 100644
index 0000000..25c3c91
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2011, 2012 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.tests.nodes;
+
+import org.eclipse.emf.common.util.EList;
+
+/**
+ * <!-- begin-user-doc -->
+ * A representation of the model object '<em><b>Node Multi Valued Non Unique Attribute</b></em>'.
+ * <!-- end-user-doc -->
+ *
+ * <p>
+ * The following features are supported:
+ * </p>
+ * <ul>
+ *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
+ * </ul>
+ *
+ * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValuedNonUniqueAttribute()
+ * @model
+ * @generated
+ */
+public interface NodeMultiValuedNonUniqueAttribute extends Node {
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	String copyright = "Copyright (c) 2011, 2012 Obeo.\r\nAll rights reserved. This program and the accompanying materials\r\nare made available under the terms of the Eclipse Public License v1.0\r\nwhich accompanies this distribution, and is available at\r\nhttp://www.eclipse.org/legal/epl-v10.html\r\n\r\nContributors:\r\n    Obeo - initial API and implementation"; //$NON-NLS-1$
+
+	/**
+	 * Returns the value of the '<em><b>Multi Valued Attribute</b></em>' attribute list.
+	 * The list contents are of type {@link java.lang.String}.
+	 * <!-- begin-user-doc -->
+	 * <p>
+	 * If the meaning of the '<em>Multi Valued Attribute</em>' attribute list isn't clear,
+	 * there really should be more of a description here...
+	 * </p>
+	 * <!-- end-user-doc -->
+	 * @return the value of the '<em>Multi Valued Attribute</em>' attribute list.
+	 * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute()
+	 * @model unique="false"
+	 * @generated
+	 */
+	EList<String> getMultiValuedAttribute();
+
+} // NodeMultiValuedNonUniqueAttribute
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java
index 64526dd..c66759e 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java
@@ -19,11 +19,11 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultipleContainment#getContainmentRef2 <em>Containment Ref2</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultipleContainment#getContainmentRef3 <em>Containment Ref3</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultipleContainment()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java
index 836a13a..2cf9120 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java
@@ -19,11 +19,11 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefManyToMany#getSource <em>Source</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefManyToMany#getDestination <em>Destination</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeOppositeRefManyToMany()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java
index ce511a5..4b6d888 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java
@@ -19,11 +19,11 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToMany#getSource <em>Source</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToMany#getDestination <em>Destination</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeOppositeRefOneToMany()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java
index 4531296..49d09da 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java
@@ -18,11 +18,11 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToOne#getSource <em>Source</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToOne#getDestination <em>Destination</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeOppositeRefOneToOne()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java
index 7a4942d..178bf0b 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java
@@ -18,10 +18,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueAttribute#getSingleValuedAttribute <em>Single Valued Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueAttribute()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java
index 11c0475..20b4479 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java
@@ -18,10 +18,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueContainment#getSingleValueContainment <em>Single Value Containment</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueContainment()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java
index 0fc9a5a..cd69bf4 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java
@@ -18,10 +18,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueEEnumAttribute#getSinglevalueEEnumAttribute <em>Singlevalue EEnum Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueEEnumAttribute()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java
index 598afc8..07173a3 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java
@@ -18,10 +18,10 @@
  *
  * <p>
  * The following features are supported:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueReference#getSingleValuedReference <em>Single Valued Reference</em>}</li>
  * </ul>
- * </p>
  *
  * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueReference()
  * @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java
index 9827080..eb42023 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java
@@ -82,6 +82,15 @@
 	NodeMultiValuedAttribute createNodeMultiValuedAttribute();
 
 	/**
+	 * Returns a new object of class '<em>Node Multi Valued Non Unique Attribute</em>'.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @return a new object of class '<em>Node Multi Valued Non Unique Attribute</em>'.
+	 * @generated
+	 */
+	NodeMultiValuedNonUniqueAttribute createNodeMultiValuedNonUniqueAttribute();
+
+	/**
 	 * Returns a new object of class '<em>Node Single Value Reference</em>'.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java
index f1237c9..57e2cf7 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java
@@ -310,6 +310,52 @@
 	int NODE_MULTI_VALUED_ATTRIBUTE_FEATURE_COUNT = NODE_FEATURE_COUNT + 1;
 
 	/**
+	 * The meta object id for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl <em>Node Multi Valued Non Unique Attribute</em>}' class.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl
+	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValuedNonUniqueAttribute()
+	 * @generated
+	 */
+	int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE = 5;
+
+	/**
+	 * The feature id for the '<em><b>Name</b></em>' attribute.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 * @ordered
+	 */
+	int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__NAME = NODE__NAME;
+
+	/**
+	 * The feature id for the '<em><b>Containment Ref1</b></em>' containment reference list.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 * @ordered
+	 */
+	int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__CONTAINMENT_REF1 = NODE__CONTAINMENT_REF1;
+
+	/**
+	 * The feature id for the '<em><b>Multi Valued Attribute</b></em>' attribute list.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 * @ordered
+	 */
+	int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE = NODE_FEATURE_COUNT + 0;
+
+	/**
+	 * The number of structural features of the '<em>Node Multi Valued Non Unique Attribute</em>' class.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 * @ordered
+	 */
+	int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE_FEATURE_COUNT = NODE_FEATURE_COUNT + 1;
+
+	/**
 	 * The meta object id for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueReferenceImpl <em>Node Single Value Reference</em>}' class.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
@@ -317,7 +363,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeSingleValueReference()
 	 * @generated
 	 */
-	int NODE_SINGLE_VALUE_REFERENCE = 5;
+	int NODE_SINGLE_VALUE_REFERENCE = 6;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -363,7 +409,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValueReference()
 	 * @generated
 	 */
-	int NODE_MULTI_VALUE_REFERENCE = 6;
+	int NODE_MULTI_VALUE_REFERENCE = 7;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -409,7 +455,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeOppositeRefOneToOne()
 	 * @generated
 	 */
-	int NODE_OPPOSITE_REF_ONE_TO_ONE = 7;
+	int NODE_OPPOSITE_REF_ONE_TO_ONE = 8;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -464,7 +510,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeOppositeRefOneToMany()
 	 * @generated
 	 */
-	int NODE_OPPOSITE_REF_ONE_TO_MANY = 8;
+	int NODE_OPPOSITE_REF_ONE_TO_MANY = 9;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -519,7 +565,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeOppositeRefManyToMany()
 	 * @generated
 	 */
-	int NODE_OPPOSITE_REF_MANY_TO_MANY = 9;
+	int NODE_OPPOSITE_REF_MANY_TO_MANY = 10;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -574,7 +620,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeFeatureMapContainment()
 	 * @generated
 	 */
-	int NODE_FEATURE_MAP_CONTAINMENT = 10;
+	int NODE_FEATURE_MAP_CONTAINMENT = 11;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -638,7 +684,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeFeatureMapNonContainment()
 	 * @generated
 	 */
-	int NODE_FEATURE_MAP_NON_CONTAINMENT = 11;
+	int NODE_FEATURE_MAP_NON_CONTAINMENT = 12;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -702,7 +748,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeFeatureMapContainment2()
 	 * @generated
 	 */
-	int NODE_FEATURE_MAP_CONTAINMENT2 = 12;
+	int NODE_FEATURE_MAP_CONTAINMENT2 = 13;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -767,7 +813,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeSingleValueEEnumAttribute()
 	 * @generated
 	 */
-	int NODE_SINGLE_VALUE_EENUM_ATTRIBUTE = 13;
+	int NODE_SINGLE_VALUE_EENUM_ATTRIBUTE = 14;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -813,7 +859,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValueEEnumAttribute()
 	 * @generated
 	 */
-	int NODE_MULTI_VALUE_EENUM_ATTRIBUTE = 14;
+	int NODE_MULTI_VALUE_EENUM_ATTRIBUTE = 15;
 
 	/**
 	 * The feature id for the '<em><b>Name</b></em>' attribute.
@@ -859,7 +905,7 @@
 	 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeEnum()
 	 * @generated
 	 */
-	int NODE_ENUM = 15;
+	int NODE_ENUM = 16;
 
 
 	/**
@@ -990,6 +1036,27 @@
 	EAttribute getNodeMultiValuedAttribute_MultiValuedAttribute();
 
 	/**
+	 * Returns the meta object for class '{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute <em>Node Multi Valued Non Unique Attribute</em>}'.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @return the meta object for class '<em>Node Multi Valued Non Unique Attribute</em>'.
+	 * @see org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute
+	 * @generated
+	 */
+	EClass getNodeMultiValuedNonUniqueAttribute();
+
+	/**
+	 * Returns the meta object for the attribute list '{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute#getMultiValuedAttribute <em>Multi Valued Attribute</em>}'.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @return the meta object for the attribute list '<em>Multi Valued Attribute</em>'.
+	 * @see org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute#getMultiValuedAttribute()
+	 * @see #getNodeMultiValuedNonUniqueAttribute()
+	 * @generated
+	 */
+	EAttribute getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute();
+
+	/**
 	 * Returns the meta object for class '{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueReference <em>Node Single Value Reference</em>}'.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
@@ -1437,6 +1504,24 @@
 		EAttribute NODE_MULTI_VALUED_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE = eINSTANCE.getNodeMultiValuedAttribute_MultiValuedAttribute();
 
 		/**
+		 * The meta object literal for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl <em>Node Multi Valued Non Unique Attribute</em>}' class.
+		 * <!-- begin-user-doc -->
+		 * <!-- end-user-doc -->
+		 * @see org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl
+		 * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValuedNonUniqueAttribute()
+		 * @generated
+		 */
+		EClass NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE = eINSTANCE.getNodeMultiValuedNonUniqueAttribute();
+
+		/**
+		 * The meta object literal for the '<em><b>Multi Valued Attribute</b></em>' attribute list feature.
+		 * <!-- begin-user-doc -->
+		 * <!-- end-user-doc -->
+		 * @generated
+		 */
+		EAttribute NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE = eINSTANCE.getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute();
+
+		/**
 		 * The meta object literal for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueReferenceImpl <em>Node Single Value Reference</em>}' class.
 		 * <!-- begin-user-doc -->
 		 * <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java
index d3e60c8..3906921 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java
@@ -29,12 +29,12 @@
  * <em><b>Node Feature Map Containment2</b></em>'. <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainment2Impl#getMap2 <em>Map2</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainment2Impl#getMultiple <em>Multiple</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainment2Impl#getSingle <em>Single</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java
index 2cc9138..2afbd09 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java
@@ -29,12 +29,12 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainmentImpl#getMap <em>Map</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainmentImpl#getFirstKey <em>First Key</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainmentImpl#getSecondKey <em>Second Key</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java
index 91f1ddf..41b092a 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java
@@ -29,12 +29,12 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapNonContainmentImpl#getMapNC <em>Map NC</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapNonContainmentImpl#getFirstKeyNC <em>First Key NC</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapNonContainmentImpl#getSecondKeyNC <em>Second Key NC</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java
index d89af6d..c33ddba 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java
@@ -30,11 +30,11 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeImpl#getName <em>Name</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeImpl#getContainmentRef1 <em>Containment Ref1</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java
index b0c2475..758bbe3 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java
@@ -28,10 +28,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValueEEnumAttributeImpl#getMultiValueEEnumAttribute <em>Multi Value EEnum Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java
index 1193f31..1e110c3 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java
@@ -25,10 +25,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValueReferenceImpl#getMultiValuedReference <em>Multi Valued Reference</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java
index cef4fa91..f7e4db4 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java
@@ -24,10 +24,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedAttributeImpl#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java
new file mode 100644
index 0000000..474b743
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java
@@ -0,0 +1,162 @@
+/**
+ * Copyright (c) 2011, 2012 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.tests.nodes.impl;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.util.EList;
+
+import org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute;
+import org.eclipse.emf.compare.tests.nodes.NodesPackage;
+
+import org.eclipse.emf.ecore.EClass;
+
+import org.eclipse.emf.ecore.util.EDataTypeEList;
+
+/**
+ * <!-- begin-user-doc -->
+ * An implementation of the model object '<em><b>Node Multi Valued Non Unique Attribute</b></em>'.
+ * <!-- end-user-doc -->
+ * <p>
+ * The following features are implemented:
+ * </p>
+ * <ul>
+ *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
+ * </ul>
+ *
+ * @generated
+ */
+public class NodeMultiValuedNonUniqueAttributeImpl extends NodeImpl implements NodeMultiValuedNonUniqueAttribute {
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	public static final String copyright = "Copyright (c) 2011, 2012 Obeo.\r\nAll rights reserved. This program and the accompanying materials\r\nare made available under the terms of the Eclipse Public License v1.0\r\nwhich accompanies this distribution, and is available at\r\nhttp://www.eclipse.org/legal/epl-v10.html\r\n\r\nContributors:\r\n    Obeo - initial API and implementation"; //$NON-NLS-1$
+
+	/**
+	 * The cached value of the '{@link #getMultiValuedAttribute() <em>Multi Valued Attribute</em>}' attribute list.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @see #getMultiValuedAttribute()
+	 * @generated
+	 * @ordered
+	 */
+	protected EList<String> multiValuedAttribute;
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected NodeMultiValuedNonUniqueAttributeImpl() {
+		super();
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	protected EClass eStaticClass() {
+		return NodesPackage.Literals.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE;
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	public EList<String> getMultiValuedAttribute() {
+		if (multiValuedAttribute == null) {
+			multiValuedAttribute = new EDataTypeEList<String>(String.class, this, NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE);
+		}
+		return multiValuedAttribute;
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public Object eGet(int featureID, boolean resolve, boolean coreType) {
+		switch (featureID) {
+			case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+				return getMultiValuedAttribute();
+		}
+		return super.eGet(featureID, resolve, coreType);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@SuppressWarnings("unchecked")
+	@Override
+	public void eSet(int featureID, Object newValue) {
+		switch (featureID) {
+			case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+				getMultiValuedAttribute().clear();
+				getMultiValuedAttribute().addAll((Collection<? extends String>)newValue);
+				return;
+		}
+		super.eSet(featureID, newValue);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public void eUnset(int featureID) {
+		switch (featureID) {
+			case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+				getMultiValuedAttribute().clear();
+				return;
+		}
+		super.eUnset(featureID);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public boolean eIsSet(int featureID) {
+		switch (featureID) {
+			case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+				return multiValuedAttribute != null && !multiValuedAttribute.isEmpty();
+		}
+		return super.eIsSet(featureID);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public String toString() {
+		if (eIsProxy()) return super.toString();
+
+		StringBuffer result = new StringBuffer(super.toString());
+		result.append(" (multiValuedAttribute: "); //$NON-NLS-1$
+		result.append(multiValuedAttribute);
+		result.append(')');
+		return result.toString();
+	}
+
+} //NodeMultiValuedNonUniqueAttributeImpl
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java
index 1f1c588..ef72bfc 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java
@@ -28,11 +28,11 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultipleContainmentImpl#getContainmentRef2 <em>Containment Ref2</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultipleContainmentImpl#getContainmentRef3 <em>Containment Ref3</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java
index 8069746..efa564f 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java
@@ -27,11 +27,11 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefManyToManyImpl#getSource <em>Source</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefManyToManyImpl#getDestination <em>Destination</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java
index a37ca2c..e6de815 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java
@@ -29,11 +29,11 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToManyImpl#getSource <em>Source</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToManyImpl#getDestination <em>Destination</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java
index 7f906e1..eada64e 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java
@@ -24,11 +24,11 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToOneImpl#getSource <em>Source</em>}</li>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToOneImpl#getDestination <em>Destination</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java
index 5deaeab..d8a0fc1 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java
@@ -22,10 +22,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueAttributeImpl#getSingleValuedAttribute <em>Single Valued Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java
index a7d8ed3..fc194f1 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java
@@ -25,10 +25,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueContainmentImpl#getSingleValueContainment <em>Single Value Containment</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java
index 81a1374..ab52264 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java
@@ -26,10 +26,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueEEnumAttributeImpl#getSinglevalueEEnumAttribute <em>Singlevalue EEnum Attribute</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java
index c282695..2bd13d0 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java
@@ -24,10 +24,10 @@
  * <!-- end-user-doc -->
  * <p>
  * The following features are implemented:
+ * </p>
  * <ul>
  *   <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueReferenceImpl#getSingleValuedReference <em>Single Valued Reference</em>}</li>
  * </ul>
- * </p>
  *
  * @generated
  */
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java
index f0d415e..c59ce29 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java
@@ -77,6 +77,7 @@
 			case NodesPackage.NODE_SINGLE_VALUE_CONTAINMENT: return createNodeSingleValueContainment();
 			case NodesPackage.NODE_SINGLE_VALUE_ATTRIBUTE: return createNodeSingleValueAttribute();
 			case NodesPackage.NODE_MULTI_VALUED_ATTRIBUTE: return createNodeMultiValuedAttribute();
+			case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE: return createNodeMultiValuedNonUniqueAttribute();
 			case NodesPackage.NODE_SINGLE_VALUE_REFERENCE: return createNodeSingleValueReference();
 			case NodesPackage.NODE_MULTI_VALUE_REFERENCE: return createNodeMultiValueReference();
 			case NodesPackage.NODE_OPPOSITE_REF_ONE_TO_ONE: return createNodeOppositeRefOneToOne();
@@ -177,6 +178,16 @@
 	 * <!-- end-user-doc -->
 	 * @generated
 	 */
+	public NodeMultiValuedNonUniqueAttribute createNodeMultiValuedNonUniqueAttribute() {
+		NodeMultiValuedNonUniqueAttributeImpl nodeMultiValuedNonUniqueAttribute = new NodeMultiValuedNonUniqueAttributeImpl();
+		return nodeMultiValuedNonUniqueAttribute;
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
 	public NodeSingleValueReference createNodeSingleValueReference() {
 		NodeSingleValueReferenceImpl nodeSingleValueReference = new NodeSingleValueReferenceImpl();
 		return nodeSingleValueReference;
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java
index a081f74..48f3eaf 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java
@@ -18,6 +18,7 @@
 import org.eclipse.emf.compare.tests.nodes.NodeMultiValueEEnumAttribute;
 import org.eclipse.emf.compare.tests.nodes.NodeMultiValueReference;
 import org.eclipse.emf.compare.tests.nodes.NodeMultiValuedAttribute;
+import org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute;
 import org.eclipse.emf.compare.tests.nodes.NodeMultipleContainment;
 import org.eclipse.emf.compare.tests.nodes.NodeOppositeRefManyToMany;
 import org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToMany;
@@ -91,6 +92,13 @@
 	 * <!-- end-user-doc -->
 	 * @generated
 	 */
+	private EClass nodeMultiValuedNonUniqueAttributeEClass = null;
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
 	private EClass nodeSingleValueReferenceEClass = null;
 
 	/**
@@ -337,6 +345,24 @@
 	 * <!-- end-user-doc -->
 	 * @generated
 	 */
+	public EClass getNodeMultiValuedNonUniqueAttribute() {
+		return nodeMultiValuedNonUniqueAttributeEClass;
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	public EAttribute getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute() {
+		return (EAttribute)nodeMultiValuedNonUniqueAttributeEClass.getEStructuralFeatures().get(0);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
 	public EClass getNodeSingleValueReference() {
 		return nodeSingleValueReferenceEClass;
 	}
@@ -647,6 +673,9 @@
 		nodeMultiValuedAttributeEClass = createEClass(NODE_MULTI_VALUED_ATTRIBUTE);
 		createEAttribute(nodeMultiValuedAttributeEClass, NODE_MULTI_VALUED_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE);
 
+		nodeMultiValuedNonUniqueAttributeEClass = createEClass(NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE);
+		createEAttribute(nodeMultiValuedNonUniqueAttributeEClass, NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE);
+
 		nodeSingleValueReferenceEClass = createEClass(NODE_SINGLE_VALUE_REFERENCE);
 		createEReference(nodeSingleValueReferenceEClass, NODE_SINGLE_VALUE_REFERENCE__SINGLE_VALUED_REFERENCE);
 
@@ -722,6 +751,7 @@
 		nodeSingleValueContainmentEClass.getESuperTypes().add(this.getNode());
 		nodeSingleValueAttributeEClass.getESuperTypes().add(this.getNode());
 		nodeMultiValuedAttributeEClass.getESuperTypes().add(this.getNode());
+		nodeMultiValuedNonUniqueAttributeEClass.getESuperTypes().add(this.getNode());
 		nodeSingleValueReferenceEClass.getESuperTypes().add(this.getNode());
 		nodeMultiValueReferenceEClass.getESuperTypes().add(this.getNode());
 		nodeOppositeRefOneToOneEClass.getESuperTypes().add(this.getNode());
@@ -751,6 +781,9 @@
 		initEClass(nodeMultiValuedAttributeEClass, NodeMultiValuedAttribute.class, "NodeMultiValuedAttribute", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
 		initEAttribute(getNodeMultiValuedAttribute_MultiValuedAttribute(), ecorePackage.getEString(), "multiValuedAttribute", null, 0, -1, NodeMultiValuedAttribute.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
 
+		initEClass(nodeMultiValuedNonUniqueAttributeEClass, NodeMultiValuedNonUniqueAttribute.class, "NodeMultiValuedNonUniqueAttribute", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
+		initEAttribute(getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute(), ecorePackage.getEString(), "multiValuedAttribute", null, 0, -1, NodeMultiValuedNonUniqueAttribute.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, !IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
+
 		initEClass(nodeSingleValueReferenceEClass, NodeSingleValueReference.class, "NodeSingleValueReference", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
 		initEReference(getNodeSingleValueReference_SingleValuedReference(), this.getNode(), null, "singleValuedReference", null, 0, 1, NodeSingleValueReference.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
 
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java
index 7f5d97b..612e266 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java
@@ -103,6 +103,10 @@
 				return createNodeMultiValuedAttributeAdapter();
 			}
 			@Override
+			public Adapter caseNodeMultiValuedNonUniqueAttribute(NodeMultiValuedNonUniqueAttribute object) {
+				return createNodeMultiValuedNonUniqueAttributeAdapter();
+			}
+			@Override
 			public Adapter caseNodeSingleValueReference(NodeSingleValueReference object) {
 				return createNodeSingleValueReferenceAdapter();
 			}
@@ -233,6 +237,20 @@
 	}
 
 	/**
+	 * Creates a new adapter for an object of class '{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute <em>Node Multi Valued Non Unique Attribute</em>}'.
+	 * <!-- begin-user-doc -->
+	 * This default implementation returns null so that we can easily ignore cases;
+	 * it's useful to ignore a case when inheritance will catch all the cases anyway.
+	 * <!-- end-user-doc -->
+	 * @return the new adapter.
+	 * @see org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute
+	 * @generated
+	 */
+	public Adapter createNodeMultiValuedNonUniqueAttributeAdapter() {
+		return null;
+	}
+
+	/**
 	 * Creates a new adapter for an object of class '{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueReference <em>Node Single Value Reference</em>}'.
 	 * <!-- begin-user-doc -->
 	 * This default implementation returns null so that we can easily ignore cases;
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java
index 183d919..6b8ea51 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java
@@ -132,6 +132,13 @@
 				if (result == null) result = defaultCase(theEObject);
 				return result;
 			}
+			case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE: {
+				NodeMultiValuedNonUniqueAttribute nodeMultiValuedNonUniqueAttribute = (NodeMultiValuedNonUniqueAttribute)theEObject;
+				T result = caseNodeMultiValuedNonUniqueAttribute(nodeMultiValuedNonUniqueAttribute);
+				if (result == null) result = caseNode(nodeMultiValuedNonUniqueAttribute);
+				if (result == null) result = defaultCase(theEObject);
+				return result;
+			}
 			case NodesPackage.NODE_SINGLE_VALUE_REFERENCE: {
 				NodeSingleValueReference nodeSingleValueReference = (NodeSingleValueReference)theEObject;
 				T result = caseNodeSingleValueReference(nodeSingleValueReference);
@@ -282,6 +289,21 @@
 	}
 
 	/**
+	 * Returns the result of interpreting the object as an instance of '<em>Node Multi Valued Non Unique Attribute</em>'.
+	 * <!-- begin-user-doc -->
+	 * This implementation returns null;
+	 * returning a non-null result will terminate the switch.
+	 * <!-- end-user-doc -->
+	 * @param object the target of the switch.
+	 * @return the result of interpreting the object as an instance of '<em>Node Multi Valued Non Unique Attribute</em>'.
+	 * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+	 * @generated
+	 */
+	public T caseNodeMultiValuedNonUniqueAttribute(NodeMultiValuedNonUniqueAttribute object) {
+		return null;
+	}
+
+	/**
 	 * Returns the result of interpreting the object as an instance of '<em>Node Single Value Reference</em>'.
 	 * <!-- begin-user-doc -->
 	 * This implementation returns null;
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java
new file mode 100644
index 0000000..58abb9e
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java
@@ -0,0 +1,600 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Laurent Goubet - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.diff;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.common.util.BasicMonitor;
+import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.ConflictKind;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceKind;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.EMFCompare;
+import org.eclipse.emf.compare.merge.IMerger;
+import org.eclipse.emf.compare.scope.DefaultComparisonScope;
+import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.compare.tests.diff.data.nonuniquemultivaluedattribute.NonUniqueMultiValuedAttributeInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.junit.Test;
+
+/*
+ * non-unique multi-valued attributes may contain duplicate values and thus present particularities for
+ * both the differencing process and the conflict detection process. During detection, we need to consider
+ * that a if one side has two identical values and the other has three, then there is an addition (and not
+ * a move has was previously detected). Furthermore, we will consider that adding the same value on both
+ * sides of a three-way comparison is a pseudo-conflict (previously, there was no conflict at all since
+ * non-unique values can have the same value more than once and thus the merge of such differences could
+ * be done without issues). The comparison path for 3-way and 2-way being different, we need to make sure
+ * both situations are tested.
+ */
+@SuppressWarnings("nls")
+public class NonUniqueMultiValuedAttributeTest {
+	private NonUniqueMultiValuedAttributeInputData input = new NonUniqueMultiValuedAttributeInputData();
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseA3WayDiff() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseAOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+		Diff diff1 = differences.get(0); // ADD 3.03030303E-4
+		Diff diff2 = differences.get(1); // ADD 0.0
+		Diff diff3 = differences.get(2); // DELETE 1.69714
+		Diff diff4 = differences.get(3); // DELETE 5.985E-4
+
+		assertTrue(diff1 instanceof AttributeChange);
+		assertTrue(diff2 instanceof AttributeChange);
+		assertTrue(diff3 instanceof AttributeChange);
+		assertTrue(diff4 instanceof AttributeChange);
+		assertEquals("3.03030303E-4", ((AttributeChange)diff1).getValue());
+		assertEquals("0.0", ((AttributeChange)diff2).getValue());
+		assertEquals("1.69714", ((AttributeChange)diff3).getValue());
+		assertEquals("5.985E-4", ((AttributeChange)diff4).getValue());
+		assertEquals(DifferenceKind.ADD, diff1.getKind());
+		assertEquals(DifferenceKind.ADD, diff2.getKind());
+		assertEquals(DifferenceKind.DELETE, diff3.getKind());
+		assertEquals(DifferenceKind.DELETE, diff4.getKind());
+		assertEquals(DifferenceSource.RIGHT, diff1.getSource());
+		assertEquals(DifferenceSource.RIGHT, diff2.getSource());
+		assertEquals(DifferenceSource.RIGHT, diff3.getSource());
+		assertEquals(DifferenceSource.RIGHT, diff4.getSource());
+
+		// No conflicts
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseA2WayDiff() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+		Diff diff1 = differences.get(0); // ADD 1.69714
+		Diff diff2 = differences.get(1); // ADD 5.985E-4
+		Diff diff3 = differences.get(2); // DELETE 3.03030303E-4
+		Diff diff4 = differences.get(3); // DELETE 0.0
+
+		assertTrue(diff1 instanceof AttributeChange);
+		assertTrue(diff2 instanceof AttributeChange);
+		assertTrue(diff3 instanceof AttributeChange);
+		assertTrue(diff4 instanceof AttributeChange);
+		assertEquals("1.69714", ((AttributeChange)diff1).getValue());
+		assertEquals("5.985E-4", ((AttributeChange)diff2).getValue());
+		assertEquals("3.03030303E-4", ((AttributeChange)diff3).getValue());
+		assertEquals("0.0", ((AttributeChange)diff4).getValue());
+		assertEquals(DifferenceKind.ADD, diff1.getKind());
+		assertEquals(DifferenceKind.ADD, diff2.getKind());
+		assertEquals(DifferenceKind.DELETE, diff3.getKind());
+		assertEquals(DifferenceKind.DELETE, diff4.getKind());
+		assertEquals(DifferenceSource.LEFT, diff1.getSource());
+		assertEquals(DifferenceSource.LEFT, diff2.getSource());
+		assertEquals(DifferenceSource.LEFT, diff3.getSource());
+		assertEquals(DifferenceSource.LEFT, diff4.getSource());
+
+		// No conflicts
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseA3WayMergeRtL() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseAOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseA3WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have 8 differences, paired in 4 pseudo-conflicts
+		assertEquals(8, comparison.getDifferences().size());
+		assertEquals(4, comparison.getConflicts().size());
+
+		for (Conflict c : comparison.getConflicts()) {
+			assertEquals(2, c.getDifferences().size());
+			assertEquals(ConflictKind.PSEUDO, c.getKind());
+		}
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseA2WayMergeRtL() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseA2WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have no differences left
+		assertEquals(0, comparison.getDifferences().size());
+		assertEquals(0, comparison.getConflicts().size());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseA3WayMergeLtR() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseAOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseA3WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have 0 differences
+		// (all diffs were on the right side so we cancelled them by merging)
+		assertTrue(comparison.getDifferences().isEmpty());
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseA2WayMergeLtR() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseA2WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have no differences left
+		assertEquals(0, comparison.getDifferences().size());
+		assertEquals(0, comparison.getConflicts().size());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseB3WayDiff() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseBOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 3 differences
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(3, differences.size());
+		Diff diff1 = differences.get(0); // MOVE a
+		Diff diff2 = differences.get(1); // ADD a
+		Diff diff3 = differences.get(2); // DELETE b
+
+		assertTrue(diff1 instanceof AttributeChange);
+		assertTrue(diff2 instanceof AttributeChange);
+		assertTrue(diff3 instanceof AttributeChange);
+		assertEquals("a", ((AttributeChange)diff1).getValue());
+		assertEquals("a", ((AttributeChange)diff2).getValue());
+		assertEquals("b", ((AttributeChange)diff3).getValue());
+		assertEquals(DifferenceKind.MOVE, diff1.getKind());
+		assertEquals(DifferenceKind.ADD, diff2.getKind());
+		assertEquals(DifferenceKind.DELETE, diff3.getKind());
+		assertEquals(DifferenceSource.RIGHT, diff1.getSource());
+		assertEquals(DifferenceSource.RIGHT, diff2.getSource());
+		assertEquals(DifferenceSource.RIGHT, diff3.getSource());
+
+		// No conflicts
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseB2WayDiff() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 3 differences
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(3, differences.size());
+		Diff diff1 = differences.get(0); // MOVE b
+		Diff diff2 = differences.get(1); // MOVE d
+		Diff diff3 = differences.get(2); // DELETE a
+
+		assertTrue(diff1 instanceof AttributeChange);
+		assertTrue(diff2 instanceof AttributeChange);
+		assertTrue(diff3 instanceof AttributeChange);
+		assertEquals("b", ((AttributeChange)diff1).getValue());
+		assertEquals("d", ((AttributeChange)diff2).getValue());
+		assertEquals("a", ((AttributeChange)diff3).getValue());
+		assertEquals(DifferenceKind.ADD, diff1.getKind());
+		assertEquals(DifferenceKind.MOVE, diff2.getKind());
+		assertEquals(DifferenceKind.DELETE, diff3.getKind());
+		assertEquals(DifferenceSource.LEFT, diff1.getSource());
+		assertEquals(DifferenceSource.LEFT, diff2.getSource());
+		assertEquals(DifferenceSource.LEFT, diff3.getSource());
+
+		// No conflicts
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseB3WayMergeRtL() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseBOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 3 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseB3WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(3, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have 6 differences, paired in 3 pseudo-conflicts
+		assertEquals(6, comparison.getDifferences().size());
+		assertEquals(3, comparison.getConflicts().size());
+
+		for (Conflict c : comparison.getConflicts()) {
+			assertEquals(2, c.getDifferences().size());
+			assertEquals(ConflictKind.PSEUDO, c.getKind());
+		}
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseB2WayMergeRtL() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 3 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseB2WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(3, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have no differences left
+		assertEquals(0, comparison.getDifferences().size());
+		assertEquals(0, comparison.getConflicts().size());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseB3WayMergeLtR() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseBOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 3 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseB3WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(3, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have 0 differences
+		// (all diffs were on the right side so we cancelled them by merging)
+		assertTrue(comparison.getDifferences().isEmpty());
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseB2WayMergeLtR() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 3 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseB2WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(3, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have no differences left
+		assertEquals(0, comparison.getDifferences().size());
+		assertEquals(0, comparison.getConflicts().size());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseC3WayDiff() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseCOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+		Diff diff1 = differences.get(0); // ADD c
+		Diff diff2 = differences.get(1); // ADD b
+		Diff diff3 = differences.get(2); // ADD b
+		Diff diff4 = differences.get(3); // MOVE d
+
+		assertTrue(diff1 instanceof AttributeChange);
+		assertTrue(diff2 instanceof AttributeChange);
+		assertTrue(diff3 instanceof AttributeChange);
+		assertTrue(diff4 instanceof AttributeChange);
+		assertEquals("c", ((AttributeChange)diff1).getValue());
+		assertEquals("b", ((AttributeChange)diff2).getValue());
+		assertEquals("b", ((AttributeChange)diff3).getValue());
+		assertEquals("d", ((AttributeChange)diff4).getValue());
+		assertEquals(DifferenceKind.ADD, diff1.getKind());
+		assertEquals(DifferenceKind.ADD, diff2.getKind());
+		assertEquals(DifferenceKind.ADD, diff3.getKind());
+		assertEquals(DifferenceKind.MOVE, diff4.getKind());
+		assertEquals(DifferenceSource.LEFT, diff1.getSource());
+		assertEquals(DifferenceSource.LEFT, diff2.getSource());
+		assertEquals(DifferenceSource.LEFT, diff3.getSource());
+		assertEquals(DifferenceSource.LEFT, diff4.getSource());
+
+		// No conflicts
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseC2WayDiff() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+		Diff diff1 = differences.get(0); // ADD c
+		Diff diff2 = differences.get(1); // ADD b
+		Diff diff3 = differences.get(2); // ADD b
+		Diff diff4 = differences.get(3); // MOVE d
+
+		assertTrue(diff1 instanceof AttributeChange);
+		assertTrue(diff2 instanceof AttributeChange);
+		assertTrue(diff3 instanceof AttributeChange);
+		assertTrue(diff4 instanceof AttributeChange);
+		assertEquals("c", ((AttributeChange)diff1).getValue());
+		assertEquals("b", ((AttributeChange)diff2).getValue());
+		assertEquals("b", ((AttributeChange)diff3).getValue());
+		assertEquals("d", ((AttributeChange)diff4).getValue());
+		assertEquals(DifferenceKind.ADD, diff1.getKind());
+		assertEquals(DifferenceKind.ADD, diff2.getKind());
+		assertEquals(DifferenceKind.ADD, diff3.getKind());
+		assertEquals(DifferenceKind.MOVE, diff4.getKind());
+		assertEquals(DifferenceSource.LEFT, diff1.getSource());
+		assertEquals(DifferenceSource.LEFT, diff2.getSource());
+		assertEquals(DifferenceSource.LEFT, diff3.getSource());
+		assertEquals(DifferenceSource.LEFT, diff4.getSource());
+
+		// No conflicts
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseC3WayMergeRtL() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseCOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseC3WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have 0 differences
+		// (all diffs were on the left side so we cancelled them by merging)
+		assertTrue(comparison.getDifferences().isEmpty());
+		assertTrue(comparison.getConflicts().isEmpty());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseC2WayMergeRtL() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseC2WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have no differences left
+		assertEquals(0, comparison.getDifferences().size());
+		assertEquals(0, comparison.getConflicts().size());
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseC3WayMergeLtR() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+		Resource origin = input.getNonUniqueMultiValuedAttributeCaseCOrigin();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseC3WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have 8 differences, paired in 4 pseudo-conflicts
+		assertEquals(8, comparison.getDifferences().size());
+		assertEquals(4, comparison.getConflicts().size());
+
+		for (Conflict c : comparison.getConflicts()) {
+			assertEquals(2, c.getDifferences().size());
+			assertEquals(ConflictKind.PSEUDO, c.getKind());
+		}
+	}
+
+	@Test
+	public void testNonUniqueMultiValuedAttributeCaseC2WayMergeLtR() throws IOException {
+		Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+		Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+
+		IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+		Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+		// We expect 4 differences and no conflict.
+		// see testNonUniqueMultiValuedAttributeCaseC2WayDiff if this fails
+		assertTrue(comparison.getConflicts().isEmpty());
+		List<Diff> differences = comparison.getDifferences();
+		assertEquals(4, differences.size());
+
+		IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+		for (Diff diff : differences) {
+			mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+					BasicMonitor.toMonitor(new NullProgressMonitor()));
+		}
+
+		comparison = EMFCompare.builder().build().compare(scope);
+		// we should now have no differences left
+		assertEquals(0, comparison.getDifferences().size());
+		assertEquals(0, comparison.getConflicts().size());
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java
index 20b610c..9289241 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java
@@ -42,7 +42,7 @@
 		Resource right = input.getSingleValueAttributePseudoConflictRight();
 		Resource origin = input.getSingleValueAttributePseudoConflictOrigin();
 
-		IComparisonScope scope = new DefaultComparisonScope(right, left, origin);
+		IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
 		Comparison comparison = EMFCompare.builder().build().compare(scope);
 
 		// There are only two differences
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java
new file mode 100644
index 0000000..beb1e80
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Laurent Goubet - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.diff.data.nonuniquemultivaluedattribute;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+@SuppressWarnings("nls")
+public class NonUniqueMultiValuedAttributeInputData extends AbstractInputData {
+	public Resource getNonUniqueMultiValuedAttributeCaseALeft() throws IOException {
+		return loadFromClassLoader("a/left.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseARight() throws IOException {
+		return loadFromClassLoader("a/right.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseAOrigin() throws IOException {
+		return loadFromClassLoader("a/origin.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseBLeft() throws IOException {
+		return loadFromClassLoader("b/left.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseBRight() throws IOException {
+		return loadFromClassLoader("b/right.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseBOrigin() throws IOException {
+		return loadFromClassLoader("b/origin.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseCLeft() throws IOException {
+		return loadFromClassLoader("c/left.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseCRight() throws IOException {
+		return loadFromClassLoader("c/right.nodes");
+	}
+
+	public Resource getNonUniqueMultiValuedAttributeCaseCOrigin() throws IOException {
+		return loadFromClassLoader("c/origin.nodes");
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes
new file mode 100644
index 0000000..f568a01
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>1.69714</multiValuedAttribute>

+  <multiValuedAttribute>5.985E-4</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes
new file mode 100644
index 0000000..f568a01
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>1.69714</multiValuedAttribute>

+  <multiValuedAttribute>5.985E-4</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes
new file mode 100644
index 0000000..54c3ee3
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>3.03030303E-4</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+  <multiValuedAttribute>0.0</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes
new file mode 100644
index 0000000..c57e03a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>c</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>d</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes
new file mode 100644
index 0000000..c57e03a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>c</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>d</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes
new file mode 100644
index 0000000..3a9edcf
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>c</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>d</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes
new file mode 100644
index 0000000..a4c3194
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>c</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>d</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes
new file mode 100644
index 0000000..35cd669
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>d</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes
new file mode 100644
index 0000000..35cd669
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>b</multiValuedAttribute>

+  <multiValuedAttribute>d</multiValuedAttribute>

+  <multiValuedAttribute>a</multiValuedAttribute>

+</nodes:NodeMultiValuedNonUniqueAttribute>

diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
index 2ecd6fa..1290f4a 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
@@ -28,6 +28,8 @@
 import org.eclipse.emf.compare.tests.diff.FeatureFilterTest;
 import org.eclipse.emf.compare.tests.diff.FeatureMapMoveDiffTest;
 import org.eclipse.emf.compare.tests.diff.LCSPerformanceTest;
+import org.eclipse.emf.compare.tests.diff.NonUniqueMultiValuedAttributeTest;
+import org.eclipse.emf.compare.tests.diff.SingleValuedAttributePseudoConflictTest;
 import org.eclipse.emf.compare.tests.diff.ThreeWayTextDiffTest;
 import org.eclipse.emf.compare.tests.diff.URIDistanceTest;
 import org.eclipse.emf.compare.tests.edit.AllEditTests;
@@ -106,7 +108,8 @@
 		RankedAdapterFactoryRegistryTest.class, ComparisonScopeAdapterTest.class,
 		EMFComparePredicatesTest.class, ImplicationsMergeTest.class, GraphTest.class,
 		ConflictImplicationsTest_Bug484579.class, PseudoConflictDetectionTest.class, ComplexMergeTest.class,
-		ConflictSearchTest.class, DiffRelationshipComputerTest.class })
+		ConflictSearchTest.class, DiffRelationshipComputerTest.class,
+		SingleValuedAttributePseudoConflictTest.class, NonUniqueMultiValuedAttributeTest.class, })
 public class AllTests {
 
 	@BeforeClass
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
index 38c2b62..38d9305 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
@@ -464,16 +464,7 @@
 		final IEqualityHelper equalityHelper = comparison.getEqualityHelper();
 
 		for (Diff candidate : refinedCandidates) {
-			final Object candidateValue;
-			if (candidate instanceof ReferenceChange) {
-				candidateValue = ((ReferenceChange)candidate).getValue();
-			} else if (candidate instanceof AttributeChange) {
-				candidateValue = ((AttributeChange)candidate).getValue();
-			} else if (candidate instanceof FeatureMapChange) {
-				candidateValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
-			} else {
-				candidateValue = null;
-			}
+			final Object candidateValue = getDiffValue(candidate);
 
 			if (diff.getMatch() == candidate.getMatch()) {
 				if (equalityHelper.matchingValues(changedValue, candidateValue)) {
@@ -655,16 +646,7 @@
 		});
 
 		for (Diff candidate : refinedCandidates) {
-			final Object candidateValue;
-			if (candidate instanceof ReferenceChange) {
-				candidateValue = ((ReferenceChange)candidate).getValue();
-			} else if (candidate instanceof AttributeChange) {
-				candidateValue = ((AttributeChange)candidate).getValue();
-			} else if (candidate instanceof FeatureMapChange) {
-				candidateValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
-			} else {
-				candidateValue = null;
-			}
+			final Object candidateValue = getDiffValue(candidate);
 
 			if (diff.getMatch() == candidate.getMatch()
 					&& comparison.getEqualityHelper().matchingValues(changedValue, candidateValue)) {
@@ -732,16 +714,7 @@
 		});
 
 		for (Diff candidate : refinedCandidates) {
-			final Object movedValue;
-			if (candidate instanceof ReferenceChange) {
-				movedValue = ((ReferenceChange)candidate).getValue();
-			} else if (candidate instanceof AttributeChange) {
-				movedValue = ((AttributeChange)candidate).getValue();
-			} else if (candidate instanceof FeatureMapChange) {
-				movedValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
-			} else {
-				movedValue = null;
-			}
+			final Object movedValue = getDiffValue(candidate);
 
 			if (comparison.getEqualityHelper().matchingValues(deletedValue, movedValue)) {
 				if (candidate.getKind() == DifferenceKind.MOVE) {
@@ -808,17 +781,15 @@
 		});
 
 		for (Diff candidate : refinedCandidates) {
-			final Object candidateValue;
-			if (candidate instanceof ReferenceChange) {
-				candidateValue = ((ReferenceChange)candidate).getValue();
-			} else if (candidate instanceof AttributeChange) {
-				candidateValue = ((AttributeChange)candidate).getValue();
-			} else if (candidate instanceof FeatureMapChange) {
-				candidateValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
-			} else {
-				candidateValue = null;
-			}
-			// No diff on non unique features : multiple same values can coexist
+			final Object candidateValue = getDiffValue(candidate);
+			/*
+			 * multiple same values can coexist on non-unique features, so we won't detect real conflicts in
+			 * such cases. However, if a value is not present in the origin but added in both left and right,
+			 * we'll consider it a pseudo conflict to avoid "noise" for the user. If the same value has been
+			 * added multiple times on the side(s), we'll only detect pseudo conflict on pairs of additions
+			 * and none if there is no longer a pair (i.e. the same value has been added one more times on one
+			 * side than in the other).
+			 */
 			if (feature.isUnique()
 					&& comparison.getEqualityHelper().matchingValues(addedValue, candidateValue)) {
 				// This is a conflict. Is it real?
@@ -840,10 +811,53 @@
 				} else {
 					conflictOn(comparison, diff, candidate, ConflictKind.REAL);
 				}
+			} else if (!feature.isUnique()) {
+				if (comparison.getEqualityHelper().matchingValues(addedValue, candidateValue)) {
+					// potential pseudo-conflict
+					// Is this candidate already paired in a pseudo conflict?
+					if (candidate.getConflict() != null
+							&& candidate.getConflict().getKind() == ConflictKind.PSEUDO) {
+						if (candidate.getConflict().getDifferences().stream()
+								.anyMatch(conflictingWith -> matchingConflictingDiff(comparison, diff,
+										conflictingWith))) {
+							// continue to next candidate
+							continue;
+						}
+					}
+					// Even if these two values haven't been added at the same index on both side, we'll
+					// consider it a pseudo-conflict.
+					conflictOn(comparison, diff, candidate, ConflictKind.PSEUDO);
+				}
 			}
 		}
 	}
 
+	private static boolean matchingConflictingDiff(Comparison comparison, Diff reference, Diff candidate) {
+		if (reference == candidate) {
+			return true;
+		}
+		if (reference.getMatch() == candidate.getMatch() && reference.getKind() == candidate.getKind()) {
+			Object referenceValue = getDiffValue(reference);
+			Object candidateValue = getDiffValue(candidate);
+			return comparison.getEqualityHelper().matchingValues(referenceValue, candidateValue);
+		}
+		return false;
+	}
+
+	private static Object getDiffValue(Diff diff) {
+		Object value;
+		if (diff instanceof ReferenceChange) {
+			value = ((ReferenceChange)diff).getValue();
+		} else if (diff instanceof AttributeChange) {
+			value = ((AttributeChange)diff).getValue();
+		} else if (diff instanceof FeatureMapChange) {
+			value = ((FeatureMap.Entry)((FeatureMapChange)diff).getValue()).getValue();
+		} else {
+			value = null;
+		}
+		return value;
+	}
+
 	/**
 	 * This will be called once for each ResourceAttachmentChange in the comparison model.
 	 * 
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
index de5c61b..d9f4c11 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
@@ -86,27 +86,29 @@
 	}
 
 	/**
-	 * Checks whether the given {@code iterable} contains the given {@code element} according to the semantics
-	 * of {@link IEqualityHelper#matchingValues(Comparison, Object, Object)}.
+	 * Checks whether the given {@code list} contains the given {@code element} according to the semantics of
+	 * {@link IEqualityHelper#matchingValues(Comparison, Object, Object)} and returns the index at which it is
+	 * positioned if applicable.
 	 * 
 	 * @param comparison
 	 *            This will be used in order to retrieve the Match for EObjects when comparing them.
-	 * @param iterable
-	 *            Iterable which content we are to check.
+	 * @param list
+	 *            List which content we are to check.
 	 * @param element
-	 *            The element we expect to be contained in {@code  iterable}.
+	 *            The element we expect to be contained in {@code list}.
 	 * @param <E>
 	 *            Type of the input iterable's content.
-	 * @return {@code true} if the given {@code iterable} contains {@code element}, {@code false} otherwise.
+	 * @return The index at which the given {@code list} contains {@code element}, {@code -1} otherwise.
 	 */
-	protected <E> boolean contains(Comparison comparison, Iterable<E> iterable, E element) {
+	protected <E> int indexOf(Comparison comparison, List<E> list, E element) {
 		final IEqualityHelper equality = comparison.getEqualityHelper();
-		for (E candidate : iterable) {
+		for (int i = 0; i < list.size(); i++) {
+			E candidate = list.get(i);
 			if (equality.matchingValues(candidate, element)) {
-				return true;
+				return i;
 			}
 		}
-		return false;
+		return -1;
 	}
 
 	/**
@@ -779,6 +781,7 @@
 
 		// Any value that is _not_ in the LCS has changed.
 
+		List<Object> originWithNoLCS = trimLCS(originValues, lcsOriginLeft, equality);
 		int lcsCursor = 0;
 		Optional<Object> lcsCurrent = getIfPresent(lcsOriginLeft, lcsCursor);
 		for (Object diffCandidate : leftValues) {
@@ -789,12 +792,15 @@
 				continue;
 			}
 
-			if (contains(comparison, originValues, diffCandidate)) {
+			int index = indexOf(comparison, originWithNoLCS, diffCandidate);
+			if (index >= 0) {
+				originWithNoLCS.remove(index);
 				if (checkOrdering) {
 					featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
 				}
 			} else if (FeatureMapUtil.isFeatureMap(feature) && diffCandidate instanceof FeatureMap.Entry) {
-				// A value of a FeatureMap changed his key
+				// A value of a FeatureMap changed its key
+				// TODO Could feature map have duplicate entries and require the same "!isUnique" treatment?
 				if (isFeatureMapEntryKeyChange(equality, (FeatureMap.Entry)diffCandidate, originValues)) {
 					featureChange(match, feature, diffCandidate, DifferenceKind.CHANGE,
 							DifferenceSource.LEFT);
@@ -809,6 +815,23 @@
 			}
 		}
 
+		// A Value that is not in the left but present in the origin has been deleted
+		List<Object> leftWithNoLCS = trimLCS(leftValues, lcsOriginLeft, equality);
+		for (Object diffCandidate : originWithNoLCS) {
+			int indexLeft = indexOf(comparison, leftWithNoLCS, diffCandidate);
+			if (indexLeft == -1) {
+				if ((feature instanceof EReference || match.getLeft() != null)
+						&& !isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
+								DifferenceSource.LEFT)) {
+					featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
+							DifferenceSource.LEFT);
+				}
+			} else if (!feature.isUnique()) {
+				leftWithNoLCS.remove(indexLeft);
+			}
+		}
+
+		originWithNoLCS = trimLCS(originValues, lcsOriginRight, equality);
 		lcsCursor = 0;
 		lcsCurrent = getIfPresent(lcsOriginRight, lcsCursor);
 		for (Object diffCandidate : rightValues) {
@@ -819,12 +842,14 @@
 				continue;
 			}
 
-			if (contains(comparison, originValues, diffCandidate)) {
+			int index = indexOf(comparison, originWithNoLCS, diffCandidate);
+			if (index >= 0) {
+				originWithNoLCS.remove(index);
 				if (checkOrdering) {
 					featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.RIGHT);
 				}
 			} else if (FeatureMapUtil.isFeatureMap(feature) && diffCandidate instanceof FeatureMap.Entry) {
-				// A value of a FeatureMap changed his key
+				// A value of a FeatureMap changed its key
 				if (isFeatureMapEntryKeyChange(equality, (FeatureMap.Entry)diffCandidate, originValues)) {
 					featureChange(match, feature, diffCandidate, DifferenceKind.CHANGE,
 							DifferenceSource.RIGHT);
@@ -839,25 +864,19 @@
 			}
 		}
 
-		// Removed from either side
-		for (Object diffCandidate : originValues) {
-			// A value that is in the origin but not in one of the side has been deleted.
-			// However, we do not want attribute changes on removed elements.
-			if (!contains(comparison, leftValues, diffCandidate)) {
-				if ((feature instanceof EReference || match.getLeft() != null)
-						&& !isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
-								DifferenceSource.LEFT)) {
-					featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
-							DifferenceSource.LEFT);
-				}
-			}
-			if (!contains(comparison, rightValues, diffCandidate)) {
+		// A Value that is not in the right but present in the origin has been deleted
+		List<Object> rightWithNoLCS = trimLCS(rightValues, lcsOriginRight, equality);
+		for (Object diffCandidate : originWithNoLCS) {
+			int indexRight = indexOf(comparison, rightWithNoLCS, diffCandidate);
+			if (indexRight == -1) {
 				if ((feature instanceof EReference || match.getRight() != null)
 						&& !isFeatureMapChangeOrMove(comparison, feature, diffCandidate, rightValues,
 								DifferenceSource.RIGHT)) {
 					featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
 							DifferenceSource.RIGHT);
 				}
+			} else if (!feature.isUnique()) {
+				rightWithNoLCS.remove(indexRight);
 			}
 		}
 	}
@@ -976,6 +995,7 @@
 
 		final List<Object> lcs = DiffUtil.longestCommonSubsequence(comparison, rightValues, leftValues);
 
+		List<Object> rightWithNoLCS = trimLCS(rightValues, lcs, equality);
 		int lcsCursor = 0;
 		Optional<Object> lcsCurrent = getIfPresent(lcs, lcsCursor);
 		for (Object diffCandidate : leftValues) {
@@ -986,7 +1006,9 @@
 				continue;
 			}
 
-			if (contains(comparison, rightValues, diffCandidate)) {
+			int index = indexOf(comparison, rightWithNoLCS, diffCandidate);
+			if (index >= 0) {
+				rightWithNoLCS.remove(index);
 				if (checkOrdering) {
 					featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
 				}
@@ -1006,25 +1028,46 @@
 			}
 		}
 
-		for (Object diffCandidate : rightValues) {
-
-			if (contains(comparison, leftValues, diffCandidate)) {
-				// skip elements which were already looked at earlier
-				continue;
-			}
-
-			// A value that is in the right but not in the left has been deleted or moved.
-			if (isFeatureMapMoveFromNonFeatureMapContainment(comparison, feature, diffCandidate, leftValues,
-					DifferenceSource.LEFT)) {
-				// add move change if the move originates from a non-feature-map containment.
-				featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
-			} else if (!isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
-					DifferenceSource.LEFT)) {
-				featureChange(match, feature, diffCandidate, DifferenceKind.DELETE, DifferenceSource.LEFT);
+		List<Object> leftWithNoLCS = trimLCS(leftValues, lcs, equality);
+		for (Object diffCandidate : rightWithNoLCS) {
+			int index = indexOf(comparison, leftWithNoLCS, diffCandidate);
+			if (index == -1) {
+				// A value that is in the right but not in the left has been deleted or moved.
+				if (isFeatureMapMoveFromNonFeatureMapContainment(comparison, feature, diffCandidate,
+						leftValues, DifferenceSource.LEFT)) {
+					// add move change if the move originates from a non-feature-map containment.
+					featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
+				} else if (!isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
+						DifferenceSource.LEFT)) {
+					featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
+							DifferenceSource.LEFT);
+				}
+			} else if (!feature.isUnique()) {
+				leftWithNoLCS.remove(index);
 			}
 		}
 	}
 
+	private List<Object> trimLCS(List<Object> source, List<Object> lcs, IEqualityHelper equalityHelper) {
+		List<Object> result = new ArrayList<>();
+		Iterator<Object> sourceIterator = source.iterator();
+		int lcsCursor = 0;
+		Optional<Object> lcsCurrent = getIfPresent(lcs, lcsCursor);
+		while (sourceIterator.hasNext() && lcsCurrent.isPresent()) {
+			Object current = sourceIterator.next();
+			if (equalityHelper.matchingValues(current, lcsCurrent.get())) {
+				lcsCursor++;
+				lcsCurrent = getIfPresent(lcs, lcsCursor);
+			} else {
+				result.add(current);
+			}
+		}
+		while (sourceIterator.hasNext()) {
+			result.add(sourceIterator.next());
+		}
+		return result;
+	}
+
 	/**
 	 * Checks if the given candidate is a FeatureMap change of type DifferenceKind.CHANGE.
 	 *
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
index ba39f31..4695c34 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
@@ -28,6 +28,7 @@
 import org.eclipse.emf.common.util.EList;
 import org.eclipse.emf.common.util.Monitor;
 import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.ConflictKind;
 import org.eclipse.emf.compare.Diff;
 import org.eclipse.emf.compare.DifferenceKind;
 import org.eclipse.emf.ecore.EAttribute;
@@ -64,12 +65,14 @@
 		@Override
 		public void detectConflicts() {
 			EAttribute feature = diff.getAttribute();
-			// Only unique features can conflict
+			// Only unique features can have real conflicts
+			Object value = diff.getValue();
+			EList<Diff> diffsInSameMatch = diff.getMatch().getDifferences();
+			Iterable<Diff> conflictCandidates = Iterables.filter(diffsInSameMatch,
+					and(possiblyConflictingWith(diff), instanceOf(AttributeChange.class), onFeature(feature),
+							ofKind(ADD)));
 			if (feature.isUnique()) {
-				Object value = diff.getValue();
-				EList<Diff> diffsInSameMatch = diff.getMatch().getDifferences();
-				for (Diff candidate : Iterables.filter(diffsInSameMatch, and(possiblyConflictingWith(diff),
-						instanceOf(AttributeChange.class), onFeature(feature), ofKind(ADD)))) {
+				for (Diff candidate : conflictCandidates) {
 					Object candidateValue = ((AttributeChange)candidate).getValue();
 					if (comparison.getEqualityHelper().matchingValues(value, candidateValue)) {
 						// This is a conflict. Is it real?
@@ -80,8 +83,49 @@
 						}
 					}
 				}
+			} else {
+				/*
+				 * multiple same values can coexist on non-unique features, so we won't detect real conflicts
+				 * in such cases. However, if a value is not present in the origin but added in both left and
+				 * right, we'll consider it a pseudo conflict to avoid "noise" for the user. If the same value
+				 * has been added multiple times on the side(s), we'll only detect pseudo conflict on pairs of
+				 * additions and none if there is no longer a pair (i.e. the same value has been added one
+				 * more times on one side than in the other).
+				 */
+				for (Diff candidate : conflictCandidates) {
+					Object candidateValue = ((AttributeChange)candidate).getValue();
+					if (comparison.getEqualityHelper().matchingValues(value, candidateValue)) {
+						// potential pseudo-conflict
+						// is this candidate already paired in a conflict?
+						if (candidate.getConflict() != null
+								&& candidate.getConflict().getKind() == ConflictKind.PSEUDO) {
+							if (candidate.getConflict().getDifferences().stream()
+									.filter(AttributeChange.class::isInstance)
+									.anyMatch(conflictingWith -> matchingConflictingDiff(diff,
+											(AttributeChange)conflictingWith))) {
+								// continue to next candidate
+								continue;
+							}
+						}
+						conflict(candidate, PSEUDO);
+						// break the loop to prevent further matching add conflicts
+						break;
+					}
+				}
 			}
 		}
+
+		private boolean matchingConflictingDiff(AttributeChange reference, AttributeChange candidate) {
+			if (reference == candidate) {
+				return false;
+			}
+			if (reference.getMatch() == candidate.getMatch() && reference.getKind() == candidate.getKind()) {
+				Object referenceValue = reference.getValue();
+				Object candidateValue = candidate.getValue();
+				return comparison.getEqualityHelper().matchingValues(referenceValue, candidateValue);
+			}
+			return false;
+		}
 	}
 
 	/**
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
index 28eeff0..68dfd84 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
@@ -27,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.ListIterator;
@@ -298,20 +299,21 @@
 		final List<E> copy1 = Lists.newArrayList(sequence1);
 		final List<E> copy2 = Lists.newArrayList(sequence2);
 
-		Object[] ignoredElementsArray = Iterables.toArray(ignoredElements, Object.class);
+		List<Object> ignoredElementsList = new ArrayList<>();
+		ignoredElements.forEach(ignoredElementsList::add);
 
 		// Reduce sets
-		final List<E> prefix = trimPrefix(comparison, equalityHelper, ignoredElementsArray, copy1, copy2);
-		final List<E> suffix = trimSuffix(comparison, equalityHelper, ignoredElementsArray, copy1, copy2);
+		final List<E> prefix = trimPrefix(comparison, equalityHelper, ignoredElementsList, copy1, copy2);
+		final List<E> suffix = trimSuffix(comparison, equalityHelper, ignoredElementsList, copy1, copy2);
 
 		final List<E> subLCS;
 		// FIXME extract an interface for the LCS and properly separate these two differently typed
 		// implementations.
 		if (copy1.size() > Short.MAX_VALUE || copy2.size() > Short.MAX_VALUE) {
-			subLCS = intLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsArray, copy1,
+			subLCS = intLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsList, copy1,
 					copy2);
 		} else {
-			subLCS = shortLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsArray, copy1,
+			subLCS = shortLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsList, copy1,
 					copy2);
 		}
 
@@ -389,10 +391,13 @@
 	 *         returns.
 	 */
 	private static <E> List<E> trimPrefix(Comparison comparison, IEqualityHelper equalityHelper,
-			Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+			List<Object> ignoredElements, List<E> sequence1, List<E> sequence2) {
 		final int size1 = sequence1.size();
 		final int size2 = sequence2.size();
 
+		List<Object> ignoredElements1 = new ArrayList<>(ignoredElements);
+		List<Object> ignoredElements2 = new ArrayList<>(ignoredElements);
+
 		final List<E> prefix = Lists.newArrayList();
 		int start1 = 1;
 		int start2 = 1;
@@ -405,15 +410,17 @@
 				start1++;
 				start2++;
 			} else {
-				boolean ignore1 = contains(equalityHelper, ignoredElements, first);
-				boolean ignore2 = contains(equalityHelper, ignoredElements, second);
-				if (ignore1) {
+				int ignore1 = indexOf(equalityHelper, ignoredElements1, first);
+				if (ignore1 != -1) {
+					ignoredElements1.remove(ignore1);
 					start1++;
 				}
-				if (ignore2) {
+				int ignore2 = indexOf(equalityHelper, ignoredElements2, second);
+				if (ignore2 != -1) {
+					ignoredElements2.remove(ignore2);
 					start2++;
 				}
-				if (!ignore1 && !ignore2) {
+				if (ignore1 == -1 && ignore2 == -1) {
 					matching = false;
 				}
 			}
@@ -448,10 +455,13 @@
 	 *         returns.
 	 */
 	private static <E> List<E> trimSuffix(Comparison comparison, IEqualityHelper equalityHelper,
-			Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+			List<Object> ignoredElements, List<E> sequence1, List<E> sequence2) {
 		final int size1 = sequence1.size();
 		final int size2 = sequence2.size();
 
+		List<Object> ignoredElements1 = new ArrayList<>(ignoredElements);
+		List<Object> ignoredElements2 = new ArrayList<>(ignoredElements);
+
 		final List<E> suffix = Lists.newArrayList();
 		int end1 = size1;
 		int end2 = size2;
@@ -464,15 +474,17 @@
 				end1--;
 				end2--;
 			} else {
-				boolean ignore1 = contains(equalityHelper, ignoredElements, first);
-				boolean ignore2 = contains(equalityHelper, ignoredElements, second);
-				if (ignore1) {
+				int ignore1 = indexOf(equalityHelper, ignoredElements1, first);
+				if (ignore1 != -1) {
+					ignoredElements1.remove(ignore1);
 					end1--;
 				}
-				if (ignore2) {
+				int ignore2 = indexOf(equalityHelper, ignoredElements2, second);
+				if (ignore2 != -1) {
+					ignoredElements2.remove(ignore2);
 					end2--;
 				}
-				if (!ignore1 && !ignore2) {
+				if (ignore1 == -1 && ignore2 == -1) {
 					matching = false;
 				}
 			}
@@ -493,17 +505,16 @@
 	 *            The sequence which elements we need to compare with {@code element}.
 	 * @param element
 	 *            The element we are seeking in {@code sequence}.
-	 * @return {@code true} if the given {@code sequence} contains an element matching {@code element},
-	 *         {@code false} otherwise.
+	 * @return index of the given {@code element} in {@code sequence} if any, {@code -1} otherwise.
 	 * @see IEqualityHelper#matchingValues(Comparison, Object, Object)
 	 */
-	private static boolean contains(IEqualityHelper equalityHelper, Object[] sequence, Object element) {
-		for (Object candidate : sequence) {
-			if (equalityHelper.matchingValues(element, candidate)) {
-				return true;
+	private static int indexOf(IEqualityHelper equalityHelper, List<Object> sequence, Object element) {
+		for (int i = 0; i < sequence.size(); i++) {
+			if (equalityHelper.matchingValues(element, sequence.get(i))) {
+				return i;
 			}
 		}
-		return false;
+		return -1;
 	}
 
 	/**
@@ -526,7 +537,8 @@
 	 *         sequences.
 	 */
 	private static <E> List<E> shortLongestCommonSubsequence(Comparison comparison,
-			IEqualityHelper equalityHelper, Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+			IEqualityHelper equalityHelper, List<Object> ignoredElements, List<E> sequence1,
+			List<E> sequence2) {
 		final int size1 = sequence1.size();
 		final int size2 = sequence2.size();
 
@@ -545,7 +557,7 @@
 				} else {
 					final E second = sequence2.get(j - 1);
 					if (equalityHelper.matchingValues(first, second)
-							&& !contains(equalityHelper, ignoredElements, second)) {
+							&& indexOf(equalityHelper, ignoredElements, second) == -1) {
 						matrix[i][j] = (short)(1 + current);
 					} else {
 						matrix[i][j] = nextIfNoMatch;
@@ -597,7 +609,8 @@
 	 *         sequences.
 	 */
 	private static <E> List<E> intLongestCommonSubsequence(Comparison comparison,
-			IEqualityHelper equalityHelper, Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+			IEqualityHelper equalityHelper, List<Object> ignoredElements, List<E> sequence1,
+			List<E> sequence2) {
 		final int size1 = sequence1.size();
 		final int size2 = sequence2.size();
 
@@ -616,7 +629,7 @@
 				} else {
 					final E second = sequence2.get(j - 1);
 					if (equalityHelper.matchingValues(first, second)
-							&& !contains(equalityHelper, ignoredElements, second)) {
+							&& indexOf(equalityHelper, ignoredElements, second) == -1) {
 						matrix[i][j] = 1 + current;
 					} else {
 						matrix[i][j] = nextIfNoMatch;
@@ -718,13 +731,28 @@
 		}
 
 		ListIterator<E> sourceIterator = source.listIterator();
+		Iterator<E> lcsIterator = lcs.iterator();
+		E currentLCS = null;
+		if (lcsIterator.hasNext()) {
+			currentLCS = lcsIterator.next();
+		}
 		for (int i = 0; sourceIterator.hasNext() && (currentIndex == -1 || firstLCSIndex == -1); i++) {
 			final E sourceElement = sourceIterator.next();
-			if (currentIndex == -1 && equalityHelper.matchingValues(sourceElement, newElement)) {
-				currentIndex = i;
+			if (currentLCS != null && equalityHelper.matchingValues(sourceElement, currentLCS)) {
+				if (firstLCSIndex == -1) {
+					firstLCSIndex = i;
+				}
+				if (lcsIterator.hasNext()) {
+					currentLCS = lcsIterator.next();
+				} else {
+					currentLCS = null;
+				}
+				// If this is a part of the LCS, it cannot be the current element (might be duplicates, so we
+				// have to <continue> here)
+				continue;
 			}
-			if (firstLCSIndex == -1 && equalityHelper.matchingValues(sourceElement, firstLCS)) {
-				firstLCSIndex = i;
+			if (equalityHelper.matchingValues(sourceElement, newElement)) {
+				currentIndex = i;
 			}
 		}
 		// The list may contain duplicates, use a reverse iteration to find the last from LCS.
@@ -761,8 +789,93 @@
 	}
 
 	/**
+	 * This will try and determine the index at which a given element from the {@code source} list should be
+	 * inserted in the {@code target} list.
+	 * <p>
+	 * The expected insertion index will always be relative to the Longest Common Subsequence (LCS) between
+	 * the two given lists.
+	 * </p>
+	 * 
+	 * @param comparison
+	 *            This will be used in order to retrieve the Match for EObjects when comparing them.
+	 * @param source
+	 *            The List from which one element has to be added to the {@code target} list.
+	 * @param target
+	 *            The List into which one element from {@code source} has to be added.
+	 * @param lcs
+	 *            The precomputed LCS between these two lists.
+	 * @param currentIndexInSource
+	 *            The current index (in source) of the element we want to insert in target.
+	 * @param <E>
+	 *            Type of the sequences content.
+	 * @return The index at which {@code newElement} should be inserted in {@code target}.
+	 * @noreference This method is not intended to be referenced by clients.
+	 */
+	public static <E> int findInsertionIndexForElementAt(Comparison comparison, List<E> source,
+			List<E> target, List<E> lcs, int currentIndexInSource) {
+		final IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+
+		E firstLCS = null;
+		E lastLCS = null;
+		int lcsSize = lcs.size();
+		if (lcsSize > 0) {
+			firstLCS = lcs.get(0);
+			lastLCS = lcs.get(lcsSize - 1);
+		}
+
+		final int noLCS = -2;
+		int firstLCSIndex = -1;
+		int lastLCSIndex = -1;
+		if (firstLCS == null) {
+			// We have no LCS
+			firstLCSIndex = noLCS;
+			lastLCSIndex = noLCS;
+		}
+
+		ListIterator<E> sourceIterator = source.listIterator();
+		for (int i = 0; sourceIterator.hasNext() && firstLCSIndex == -1; i++) {
+			final E sourceElement = sourceIterator.next();
+			if (firstLCSIndex == -1 && equalityHelper.matchingValues(sourceElement, firstLCS)) {
+				firstLCSIndex = i;
+			}
+		}
+		// The list may contain duplicates, use a reverse iteration to find the last from LCS.
+		final int sourceSize = source.size();
+		sourceIterator = source.listIterator(sourceSize);
+		for (int i = sourceSize - 1; sourceIterator.hasPrevious() && lastLCSIndex == -1; i--) {
+			final E sourceElement = sourceIterator.previous();
+			if (lastLCSIndex == -1 && equalityHelper.matchingValues(lastLCS, sourceElement)) {
+				lastLCSIndex = i;
+			}
+		}
+
+		int insertionIndex = -1;
+		if (firstLCSIndex == noLCS) {
+			// We have no LCS. The two lists have no element in common. Insert at the very end of the target.
+			insertionIndex = target.size();
+		} else if (currentIndexInSource < firstLCSIndex) {
+			// The object we are to insert is before the LCS in source.
+			insertionIndex = insertBeforeLCS(target, equalityHelper, firstLCS);
+		} else if (currentIndexInSource > lastLCSIndex) {
+			// The object we are to insert is after the LCS in source.
+			insertionIndex = findInsertionIndexAfterLCS(target, equalityHelper, lastLCS);
+		} else {
+			// Our object is in-between two elements A and B of the LCS in source
+			insertionIndex = findInsertionIndexWithinLCS(source, target, equalityHelper, lcs,
+					currentIndexInSource);
+		}
+
+		// We somehow failed to determine the insertion index. Insert at the very end.
+		if (insertionIndex == -1) {
+			insertionIndex = target.size();
+		}
+
+		return insertionIndex;
+	}
+
+	/**
 	 * This will be called to try and find the insertion index for an element that is located in-between two
-	 * elements of the LCS between {@code source} and {@code target}.
+	 * elements A and B of the LCS between {@code source} and {@code target}.
 	 * 
 	 * @param source
 	 *            The List from which one element has to be added to the {@code target} list.
@@ -1240,7 +1353,7 @@
 	 * @return The list of elements that should be ignored when computing the insertion index for a new
 	 *         element in {@code candidates}.
 	 */
-	private static <E> Set<E> computeIgnoredElements(Comparison comparison, IEqualityHelper equalityHelper,
+	public static <E> Set<E> computeIgnoredElements(Comparison comparison, IEqualityHelper equalityHelper,
 			List<E> candidates, final Diff diff, boolean rightToLeft) {
 		// There is no point doing any computations if the candidates list is empty.
 		if (!candidates.isEmpty()) {
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
index 6b915f6..200e362 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
@@ -15,7 +15,11 @@
 import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEIsSet;
 import static org.eclipse.emf.compare.utils.ReferenceUtil.safeESet;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.eclipse.emf.common.util.EList;
 import org.eclipse.emf.compare.AttributeChange;
@@ -25,6 +29,7 @@
 import org.eclipse.emf.compare.Match;
 import org.eclipse.emf.compare.internal.ThreeWayTextDiff;
 import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.utils.IEqualityHelper;
 import org.eclipse.emf.ecore.EAttribute;
 import org.eclipse.emf.ecore.EEnum;
 import org.eclipse.emf.ecore.EEnumLiteral;
@@ -190,18 +195,75 @@
 			final EStructuralFeature attribute = diff.getAttribute();
 			// We have the container, attribute and value to remove.
 			if (attribute.isMany()) {
-				/*
-				 * TODO if the same value appears twice, should we try and find the one that has actually been
-				 * deleted? Will it happen that often? For now, remove the first occurence we find.
-				 */
-				final List<Object> targetList = (List<Object>)safeEGet(currentContainer, attribute);
-				targetList.remove(expectedValue);
+				if (attribute.isUnique()) {
+					final List<Object> targetList = (List<Object>)safeEGet(currentContainer, attribute);
+					targetList.remove(expectedValue);
+				} else {
+					removeNonUniqueFromTarget(diff, rightToLeft);
+				}
 			} else {
 				currentContainer.eUnset(attribute);
 			}
 		}
 	}
 
+	@SuppressWarnings("unchecked")
+	private void removeNonUniqueFromTarget(AttributeChange diff, boolean rightToLeft) {
+		Comparison comparison = diff.getMatch().getComparison();
+		IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+		EAttribute attribute = diff.getAttribute();
+
+		EObject sourceContainer;
+		EObject targetContainer;
+		if (rightToLeft) {
+			sourceContainer = diff.getMatch().getRight();
+			targetContainer = diff.getMatch().getLeft();
+		} else {
+			sourceContainer = diff.getMatch().getLeft();
+			targetContainer = diff.getMatch().getRight();
+		}
+
+		List<Object> sourceList = (List<Object>)safeEGet(sourceContainer, attribute);
+		List<Object> targetList = (List<Object>)safeEGet(targetContainer, attribute);
+		Object valueToRemove = diff.getValue();
+
+		List<Object> lcs = DiffUtil.longestCommonSubsequence(comparison, sourceList, targetList);
+
+		// The current index, in the target list, of that value
+		int currentIndexInTarget = -1;
+		Iterator<Object> lcsIteratorForTargetLookup = lcs.iterator();
+		Object currentLCS = null;
+		if (lcsIteratorForTargetLookup.hasNext()) {
+			currentLCS = lcsIteratorForTargetLookup.next();
+		}
+		for (int j = 0; j < targetList.size() && currentIndexInTarget == -1; j++) {
+			if (currentLCS == null) {
+				// we've iterated on our whole LCS.
+				// first instance of our target is the one to move.
+				if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToRemove)) {
+					currentIndexInTarget = j;
+				}
+			} else if (equalityHelper.matchingAttributeValues(targetList.get(j), currentLCS)) {
+				// this matches our current lcs item. continue to next one if any
+				if (lcsIteratorForTargetLookup.hasNext()) {
+					currentLCS = lcsIteratorForTargetLookup.next();
+				} else {
+					currentLCS = null;
+				}
+			} else {
+				// This item is not in our LCS. Is it the one we're looking for?
+				if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToRemove)) {
+					currentIndexInTarget = j;
+				}
+			}
+		}
+		// value might not exist in target list if it has already been removed or if this was a pseudo
+		// conflict deletion
+		if (currentIndexInTarget >= 0) {
+			targetList.remove(currentIndexInTarget);
+		}
+	}
+
 	/**
 	 * This will be called when trying to copy a "MOVE" diff.
 	 * 
@@ -239,36 +301,14 @@
 	 * @param rightToLeft
 	 *            Whether we should move the value in the left or right side.
 	 */
-	@SuppressWarnings("unchecked")
 	protected void doMove(AttributeChange diff, Comparison comparison, EObject expectedContainer,
 			Object expectedValue, boolean rightToLeft) {
 		final EStructuralFeature attribute = diff.getAttribute();
 		if (attribute.isMany()) {
-			// Element to move cannot be part of the LCS... or there would not be a MOVE diff
-			int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);
-			/*
-			 * However, it could still have been located "before" its new index, in which case we need to take
-			 * it into account.
-			 */
-			final List<Object> targetList = (List<Object>)safeEGet(expectedContainer, attribute);
-			final int currentIndex = targetList.indexOf(expectedValue);
-			if (insertionIndex > currentIndex) {
-				insertionIndex--;
-			}
-
-			if (targetList instanceof EList<?>) {
-				if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
-					((EList<Object>)targetList).move(targetList.size() - 1, expectedValue);
-				} else {
-					((EList<Object>)targetList).move(insertionIndex, expectedValue);
-				}
+			if (!attribute.isUnique()) {
+				doMoveNonUniqueAttribute(diff, comparison, rightToLeft);
 			} else {
-				targetList.remove(expectedValue);
-				if (insertionIndex < 0 || insertionIndex > targetList.size()) {
-					targetList.add(expectedValue);
-				} else {
-					targetList.add(insertionIndex, expectedValue);
-				}
+				doMoveUniqueAttribute(diff, comparison, expectedContainer, expectedValue, rightToLeft);
 			}
 		} else {
 			// This will never happen with the default diff engine, but may still be done from extenders
@@ -276,6 +316,147 @@
 		}
 	}
 
+	@SuppressWarnings("unchecked")
+	private void doMoveUniqueAttribute(AttributeChange diff, Comparison comparison, EObject expectedContainer,
+			Object expectedValue, boolean rightToLeft) {
+		final EStructuralFeature attribute = diff.getAttribute();
+
+		// Element to move cannot be part of the LCS... or there would not be a MOVE diff
+		int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);
+		/*
+		 * However, it could still have been located "before" its new index, in which case we need to take it
+		 * into account.
+		 */
+		final List<Object> targetList = (List<Object>)safeEGet(expectedContainer, attribute);
+		final int currentIndex = targetList.indexOf(expectedValue);
+		if (insertionIndex > currentIndex) {
+			insertionIndex--;
+		}
+
+		if (targetList instanceof EList<?>) {
+			if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
+				((EList<Object>)targetList).move(targetList.size() - 1, expectedValue);
+			} else {
+				((EList<Object>)targetList).move(insertionIndex, expectedValue);
+			}
+		} else {
+			targetList.remove(expectedValue);
+			if (insertionIndex < 0 || insertionIndex > targetList.size()) {
+				targetList.add(expectedValue);
+			} else {
+				targetList.add(insertionIndex, expectedValue);
+			}
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	private void doMoveNonUniqueAttribute(AttributeChange diff, Comparison comparison, boolean rightToLeft) {
+		IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+		EAttribute attribute = diff.getAttribute();
+
+		EObject sourceContainer;
+		EObject targetContainer;
+		if (rightToLeft) {
+			sourceContainer = diff.getMatch().getRight();
+			targetContainer = diff.getMatch().getLeft();
+		} else {
+			sourceContainer = diff.getMatch().getLeft();
+			targetContainer = diff.getMatch().getRight();
+		}
+
+		List<Object> sourceList = (List<Object>)safeEGet(sourceContainer, attribute);
+		List<Object> targetList = (List<Object>)safeEGet(targetContainer, attribute);
+		// copy this one : we'll have to modify target while iterating over this view
+		List<Object> copyTarget = new ArrayList<>(targetList);
+		Object valueToMove = diff.getValue();
+
+		Set<Object> ignoredElements = DiffUtil.computeIgnoredElements(comparison, equalityHelper, targetList,
+				diff, rightToLeft);
+		if (ignoredElements.isEmpty()) {
+			ignoredElements = Collections.singleton(valueToMove);
+		} else {
+			ignoredElements.add(valueToMove);
+		}
+		List<Object> lcs = DiffUtil.longestCommonSubsequence(comparison, ignoredElements, sourceList,
+				copyTarget);
+
+		// We need to find the current index, in the source list, of the value to move
+		int currentIndexInSource = -1;
+		Iterator<Object> lcsIteratorForSourceLookup = lcs.iterator();
+		Object currentLCS = null;
+		if (lcsIteratorForSourceLookup.hasNext()) {
+			currentLCS = lcsIteratorForSourceLookup.next();
+		}
+		for (int j = 0; j < sourceList.size() && currentIndexInSource == -1; j++) {
+			if (currentLCS == null) {
+				// we've iterated on our whole LCS.
+				// first instance of our target is the one to move.
+				if (equalityHelper.matchingAttributeValues(sourceList.get(j), valueToMove)) {
+					currentIndexInSource = j;
+				}
+			} else if (equalityHelper.matchingAttributeValues(sourceList.get(j), currentLCS)) {
+				// this matches our current lcs item. continue to next one if any
+				if (lcsIteratorForSourceLookup.hasNext()) {
+					currentLCS = lcsIteratorForSourceLookup.next();
+				} else {
+					currentLCS = null;
+				}
+			} else {
+				// This item is not in our LCS. Is it the one we're looking for?
+				if (equalityHelper.matchingAttributeValues(sourceList.get(j), valueToMove)) {
+					currentIndexInSource = j;
+				}
+			}
+		}
+		// The current index, in the target list, of that value
+		int currentIndexInTarget = -1;
+		Iterator<Object> lcsIteratorForTargetLookup = lcs.iterator();
+		currentLCS = null;
+		if (lcsIteratorForTargetLookup.hasNext()) {
+			currentLCS = lcsIteratorForTargetLookup.next();
+		}
+		for (int j = 0; j < targetList.size() && currentIndexInTarget == -1; j++) {
+			if (currentLCS == null) {
+				// we've iterated on our whole LCS.
+				// first instance of our target is the one to move.
+				if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToMove)) {
+					currentIndexInTarget = j;
+				}
+			} else if (equalityHelper.matchingAttributeValues(targetList.get(j), currentLCS)) {
+				// this matches our current lcs item. continue to next one if any
+				if (lcsIteratorForTargetLookup.hasNext()) {
+					currentLCS = lcsIteratorForTargetLookup.next();
+				} else {
+					currentLCS = null;
+				}
+			} else {
+				// This item is not in our LCS. Is it the one we're looking for?
+				if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToMove)) {
+					currentIndexInTarget = j;
+				}
+			}
+		}
+
+		// Then the index, in the target, at which this value needs to be moved
+		int insertionIndex = DiffUtil.findInsertionIndexForElementAt(comparison, sourceList, copyTarget, lcs,
+				currentIndexInSource);
+
+		if (targetList instanceof EList<?>) {
+			if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
+				((EList<Object>)targetList).move(targetList.size() - 1, currentIndexInTarget);
+			} else {
+				((EList<Object>)targetList).move(insertionIndex, currentIndexInTarget);
+			}
+		} else {
+			targetList.remove(currentIndexInTarget);
+			if (insertionIndex < 0 || insertionIndex > targetList.size()) {
+				targetList.add(valueToMove);
+			} else {
+				targetList.add(insertionIndex, valueToMove);
+			}
+		}
+	}
+
 	/**
 	 * This will be called by the merge operations in order to reset an attribute to its original value, be
 	 * that the left or right side.