diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncTest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncImageTest.php
similarity index 94%
rename from core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncTest.php
rename to core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncImageTest.php
index ac501c8..c18c982 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncTest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncImageTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\entity\Tests\EntityTranslationSyncTest.
+ * Contains \Drupal\entity\Tests\EntityTranslationSyncImageTest.
  */
 
 namespace Drupal\translation_entity\Tests;
@@ -12,9 +12,9 @@
 use Drupal\simpletest\WebTestBase;
 
 /**
- * Tests the Entity Translation field synchronization capability.
+ * Tests the Entity Translation image field synchronization capability.
  */
-class EntityTranslationSyncTest extends WebTestBase {
+class EntityTranslationSyncImageTest extends WebTestBase {
 
   /**
    * The name of the image field to test synchronization on.
@@ -46,8 +46,8 @@ class EntityTranslationSyncTest extends WebTestBase {
 
   public static function getInfo() {
     return array(
-      'name' => 'Entity translation field synchronization',
-      'description' => 'Tests the field synchronization behavior for the test entity.',
+      'name' => 'Image field synchronization',
+      'description' => 'Tests the field synchronization behavior for the image field.',
       'group' => 'Entity Translation UI',
     );
   }
@@ -112,9 +112,9 @@ protected function setupImageField() {
   }
 
   /**
-   * Tests entity field synchronization.
+   * Tests image field field synchronization.
    */
-  function testEntitySync() {
+  function testImageFieldSync() {
     $default_langcode = $this->langcodes[0];
     $langcode = $this->langcodes[1];
 
@@ -169,8 +169,8 @@ function testEntitySync() {
     // items order for both languages.
     for ($delta = 0; $delta < $this->cardinality - 1; $delta++) {
       // Simulate a field reordering: items are shifted of one position ahead.
-      // The module ensures we start from the beginning after reaching the
-      // maximum allowed delta.
+      // The modulo operator ensures we start from the beginning after reaching
+      // the maximum allowed delta.
       $index = ($delta + 1) % $this->cardinality;
 
       // Generate the item for the current image file entity and attach it to
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncUnitTest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncUnitTest.php
new file mode 100644
index 0000000..6c06d56
--- /dev/null
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSyncUnitTest.php
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\Tests\EntityTranslationSyncUnitTest.
+ */
+
+namespace Drupal\translation_entity\Tests;
+
+use Drupal\Core\Language\Language;
+use Drupal\simpletest\UnitTestBase;
+
+/**
+ * Tests the Entity Translation field synchronization algorithm.
+ */
+class EntityTranslationSyncUnitTest extends UnitTestBase {
+
+  /**
+   * The colums to be synchronized
+   *
+   * @var array
+   */
+  protected $synchronized;
+
+  /**
+   * All the field colums.
+   *
+   * @var array
+   */
+  protected $columns;
+
+  /**
+   * The available language codes.
+   *
+   * @var array
+   */
+  protected $langcodes;
+
+  /**
+   * The field cardinality.
+   *
+   * @var integer
+   */
+  protected $cardinality;
+
+  /**
+   * The unchanged field values.
+   *
+   * @var array
+   */
+  protected $unchangedFieldValues;
+
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Field synchronization',
+      'description' => 'Tests the field synchronization algorithm.',
+      'group' => 'Entity Translation UI',
+    );
+  }
+
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->synchronized = array('sync1', 'sync2');
+    $this->columns = array_merge($this->synchronized, array('value1', 'value2'));
+    $this->langcodes = array('en', 'it', 'fr', 'de', 'es');
+    $this->cardinality = mt_rand(2, 5);
+    $this->unchangedFieldValues = array();
+
+    foreach ($this->langcodes as $langcode) {
+      for ($delta = 0; $delta < $this->cardinality; $delta++) {
+        foreach ($this->columns as $column) {
+          $sync = in_array($column, $this->synchronized) && $langcode != $this->langcodes[0];
+          $value = $sync ? $this->unchangedFieldValues[$this->langcodes[0]][$delta][$column] : $langcode . '-' . $delta . '-' . $column; //$this->randomName();
+          $this->unchangedFieldValues[$langcode][$delta][$column] = $value;
+        }
+      }
+    }
+  }
+
+  /**
+   * Tests the field synchronization algorithm.
+   */
+  public function testFieldSync() {
+    // Add a new item to the source items and check that its added to all the
+    // translations.
+    $sync_langcode = $this->langcodes[mt_rand(0, count($this->langcodes) - 1)];
+    $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
+    $field_values = $this->unchangedFieldValues;
+    $item = array();
+    foreach ($this->columns as $column) {
+      $item[$column] = $this->randomName();
+    }
+    $field_values[$sync_langcode][] = $item;
+    translation_entity_sync_field($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
+    $result = TRUE;
+    foreach ($this->unchangedFieldValues as $langcode => $items) {
+      // Check that the old values are still in place.
+      for ($delta = 0; $delta < $this->cardinality; $delta++) {
+        foreach ($this->columns as $column) {
+          $result = $result && ($this->unchangedFieldValues[$langcode][$delta][$column] == $field_values[$langcode][$delta][$column]);
+        }
+      }
+      // Check that the new item is available in all languages.
+      foreach ($this->columns as $column) {
+        $result = $result && ($field_values[$langcode][$delta][$column] == $field_values[$sync_langcode][$delta][$column]);
+      }
+    }
+    $this->assertTrue($result, 'A new item has been correctly synchronized.');
+
+    // Remove an item from the source items and check that its removed from all
+    // the translations.
+    $sync_langcode = $this->langcodes[mt_rand(0, count($this->langcodes) - 1)];
+    $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
+    $field_values = $this->unchangedFieldValues;
+    $sync_delta = mt_rand(0, count($field_values[$sync_langcode]) - 1);
+    unset($field_values[$sync_langcode][$sync_delta]);
+    // Renumber deltas to start from 0.
+    $field_values[$sync_langcode] = array_values($field_values[$sync_langcode]);
+    translation_entity_sync_field($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
+    $result = TRUE;
+    foreach ($this->unchangedFieldValues as $langcode => $items) {
+      $new_delta = 0;
+      // Check that the old values are still in place.
+      for ($delta = 0; $delta < $this->cardinality; $delta++) {
+        // Skip the removed item.
+        if ($delta != $sync_delta) {
+          foreach ($this->columns as $column) {
+            $result = $result && ($this->unchangedFieldValues[$langcode][$delta][$column] == $field_values[$langcode][$new_delta][$column]);
+          }
+          $new_delta++;
+        }
+      }
+    }
+    $this->assertTrue($result, 'A removed item has been correctly synchronized.');
+
+    // Move the items around in the source items and check that they are moved
+    // in all the translations.
+    $sync_langcode = $this->langcodes[mt_rand(0, count($this->langcodes) - 1)];
+    $unchanged_items = $this->unchangedFieldValues[$sync_langcode];
+    $field_values = $this->unchangedFieldValues;
+    $field_values[$sync_langcode] = array();
+    // Scramble the items.
+    foreach ($unchanged_items as $delta => $item) {
+      $new_delta = ($delta + 1) % $this->cardinality;
+      $field_values[$sync_langcode][$new_delta] = $item;
+    }
+    // Renumber deltas to start from 0.
+    ksort($field_values[$sync_langcode]);
+    translation_entity_sync_field($field_values, $unchanged_items, $sync_langcode, $this->langcodes, $this->synchronized);
+    $result = TRUE;
+    foreach ($field_values as $langcode => $items) {
+      for ($delta = 0; $delta < $this->cardinality; $delta++) {
+        foreach ($this->columns as $column) {
+          $value = $field_values[$langcode][$delta][$column];
+          if (in_array($column, $this->synchronized)) {
+            // If we are dealing with a synchronize column the current value is
+            // supposed to be the same of the source items.
+            $result = $result && $field_values[$sync_langcode][$delta][$column] == $value;
+          }
+          else {
+            // Otherwise the values should be unchanged.
+            $old_delta = ($delta > 0 ? $delta : $this->cardinality) - 1;
+            $result = $result && $this->unchangedFieldValues[$langcode][$old_delta][$column] == $value;
+          }
+        }
+      }
+    }
+    $this->assertTrue($result, 'Scrambled items have been correctly synchronized.');
+  }
+
+}
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index dd9eef8..3b09be1 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -764,7 +764,6 @@ function translation_entity_sync(EntityInterface $entity, $sync_langcode, $origi
     // setting is set, and the field is translatable.
     if (!empty($entity->{$field_name}) && !empty($instance['settings']['translation_sync']) && field_is_translatable($entity_type, $field)) {
       $columns = isset($field['settings']['translation_sync']) ? $field['settings']['translation_sync'] : array();
-      $change_map = array();
       $source_items = $entity->{$field_name}[$sync_langcode];
 
       // If a translation is being created, the original values should be used
@@ -772,70 +771,111 @@ function translation_entity_sync(EntityInterface $entity, $sync_langcode, $origi
       // against.
       $langcode = $original_langcode ?: $sync_langcode;
       $unchanged_items = !empty($entity_unchanged->{$field_name}[$langcode]) ? $entity_unchanged->{$field_name}[$langcode] : array();
+      translation_entity_sync_field($entity->{$field_name}, $unchanged_items, $sync_langcode, array_keys($translations), $columns);
+    }
+  }
+}
+
+/**
+ * Synchronize the items of a single field.
+ *
+ * All the column values of the "active" language are compared to the unchanged
+ * values to detect any addition, removal or change in the items order.
+ * Subsequently the detected changes are performed on the field items in other
+ * available languages. For this to properly work the column values must be
+ * integer or strings. The synchronized column values are assumed to be unique
+ * among the various items, this is necessary to detect and replay changes in
+ * the order. They are also assumed to change simultanously, so that a change in
+ * any column indicates that all of them have changed.
+ *
+ * @param array $field_values
+ *   The field values to be synchronized.
+ * @param array $unchanged_items
+ *   The unchanged items ti be used to detect changes.
+ * @param string $sync_langcode
+ *   The language code of the items to use as source values.
+ * @param array $translations
+ *   An array of all the available language codes for the given field.
+ * @param array $columns
+ *   An array of column names to be synchronized.
+ */
+function translation_entity_sync_field(&$field_values, $unchanged_items, $sync_langcode, $translations, $columns) {
+  $source_items = $field_values[$sync_langcode];
+
+  // Make sure we can detect any change in the source items.
+  $change_map = array();
+
+  // By picking the maximum size between updated and unchanged items, we make
+  // sure to process also removed items.
+  $total = max(array(count($source_items), count($unchanged_items)));
+
+  // As a first step we build a map of the deltas corresponding to the column
+  // values to be synchronized. Recording both the old values and the new values
+  // will allow us to detect any change in the order of the new items for each
+  // column.
+  for ($delta = 0; $delta < $total; $delta++) {
+    foreach ($columns as $column) {
+      // Store the delta for the unchanged column value.
+      if (isset($unchanged_items[$delta][$column])) {
+        $value = $unchanged_items[$delta][$column];
+        $change_map[$column][$value]['old'] = $delta;
+      }
+      // Store the delta for the new column value.
+      if (isset($source_items[$delta][$column])) {
+        $value = $source_items[$delta][$column];
+        $change_map[$column][$value]['new'] = $delta;
+      }
+    }
+  }
 
-      // By picking the maximum size between updated and unchanged items, we
-      // make sure to process also removed items.
-      $total = max(array(count($source_items), count($unchanged_items)));
+  // Backup field values.
+  $original_field_values = $field_values;
 
-      // Make sure we can detect any change in the source items.
+  // Reset field values so that no spurious one is stored. Source values must be
+  // preserved in any case.
+  $field_values = array($sync_langcode => $source_items);
+
+  // Update field translations.
+  foreach ($translations as $langcode) {
+    // We need to synchronize only values different from the source ones.
+    if ($langcode != $sync_langcode) {
+      // By using the maximum cardinality we ensure to process removed items.
       for ($delta = 0; $delta < $total; $delta++) {
+        // By inspecting the map we built before we can tell whether a value has
+        // been created or removed. A changed value will be interpreted as a new
+        // value, in fact it did not exist before.
+        $created = TRUE;
+        $removed = TRUE;
         foreach ($columns as $column) {
-          // Store the delta for the unchanged column value.
-          if (isset($unchanged_items[$delta][$column])) {
-            $value = $unchanged_items[$delta][$column];
-            $change_map[$column][$value]['old'] = $delta;
-          }
-          // Store the delta for the new column value.
           if (isset($source_items[$delta][$column])) {
             $value = $source_items[$delta][$column];
-            $change_map[$column][$value]['new'] = $delta;
+            $created = $created && !isset($change_map[$column][$value]['old']);
+            $removed = $removed && !isset($change_map[$column][$value]['new']);
           }
         }
-      }
 
-      // Backup field values.
-      $field_values = $entity->{$field_name};
-
-      // Reset field values so that no spurious value is stored. Source values
-      // must be preserved in any case.
-      $entity->{$field_name} = array($sync_langcode => $source_items);
-
-      // Update translations.
-      foreach ($translations as $langcode => $language) {
-        // We need to synchronize only values different from the source ones.
-        if ($langcode != $sync_langcode) {
-          // Process even removed items.
-          for ($delta = 0; $delta < $total; $delta++) {
-            $created = TRUE;
-            $removed = TRUE;
-
-            foreach ($columns as $column) {
-              if (isset($source_items[$delta][$column])) {
-                $value = $source_items[$delta][$column];
-                $created = $created && !isset($change_map[$column][$value]['old']);
-                $removed = $removed && !isset($change_map[$column][$value]['new']);
-              }
-            }
-
-            // If an item has been removed we do not store its translations.
-            if ($removed) {
-              continue;
-            }
-            // If a synchronized column has changed we need to override the full
-            // items array for all languages.
-            elseif ($created) {
-              $entity->{$field_name}[$langcode][$delta] = $source_items[$delta];
-            }
-            // The current item might have been reordered.
-            elseif (!empty($change_map[$column][$value])) {
-              $old_delta = $change_map[$column][$value]['old'];
-              $new_delta = $change_map[$column][$value]['new'];
-              // If for any reason the old value is not defined for the current
-              // language we fall back to the new source value.
-              $item = isset($field_values[$langcode][$old_delta]) ? $field_values[$langcode][$old_delta] : $source_items[$new_delta];
-              $entity->{$field_name}[$langcode][$new_delta] = $item;
-            }
-          }
+        // If an item has been removed we do not store its translations.
+        if ($removed) {
+          continue;
+        }
+        // If a synchronized column has changed or has been created from scratch
+        // we need to override the full items array for all languages.
+        elseif ($created) {
+          $field_values[$langcode][$delta] = $source_items[$delta];
+        }
+        // Otherwise the current item might have been reordered. We assume that
+        // if a synchronized column changes all the other ones belonging to the
+        // same item change accordingly.
+        elseif (!empty($change_map[$column][$value])) {
+          $old_delta = $change_map[$column][$value]['old'];
+          $new_delta = $change_map[$column][$value]['new'];
+          // If for any reason the old value is not defined for the current
+          // language we fall back to the new source value, this way we ensure
+          // the new values are at least propagated to all the translations.
+          // If the value have only been reordered we just move the old one in
+          // the new position.
+          $item = isset($original_field_values[$langcode][$old_delta]) ? $original_field_values[$langcode][$old_delta] : $source_items[$new_delta];
+          $field_values[$langcode][$new_delta] = $item;
         }
       }
     }
