diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 5447e90..b524890 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -62,20 +62,6 @@
   protected $fields = array();
 
   /**
-   * Local cache for the entity language.
-   *
-   * @var \Drupal\Core\Language\Language
-   */
-  protected $language;
-
-  /**
-   * Local cache for the available language objects.
-   *
-   * @var array
-   */
-  protected $languages;
-
-  /**
    * Local cache for field definitions.
    *
    * @see ContentEntityBase::getPropertyDefinitions()
@@ -92,6 +78,13 @@
   protected $uriPlaceholderReplacements;
 
   /**
+   * Local cache for the available language objects.
+   *
+   * @var array
+   */
+  protected $languages;
+
+  /**
    * Language code identifying the entity active language.
    *
    * This is the language field accessors will use to determine which field
@@ -102,6 +95,13 @@
   protected $activeLangcode = Language::LANGCODE_DEFAULT;
 
   /**
+   * Local cache for the default language code.
+   *
+   * @var string
+   */
+  protected $defaultLangcode;
+
+  /**
    * An array of entity translation metadata.
    *
    * An associative array keyed by translation language code. Every value is an
@@ -150,14 +150,14 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans
       $this->values[$key] = $value;
     }
 
-    // Initialize translations. Ensure we have at least an entry for the entity
-    // original language.
+    // Initialize translations. Ensure we have at least an entry for the default
+    // language.
     $data = array('status' => static::TRANSLATION_EXISTING);
     $this->translations[Language::LANGCODE_DEFAULT] = $data;
+    $this->setDefaultLangcode();
     if ($translations) {
-      $default_langcode = $this->language()->id;
       foreach ($translations as $langcode) {
-        if ($langcode != $default_langcode && $langcode != Language::LANGCODE_DEFAULT) {
+        if ($langcode != $this->defaultLangcode && $langcode != Language::LANGCODE_DEFAULT) {
           $this->translations[$langcode] = $data;
         }
       }
@@ -385,50 +385,56 @@ public function get($property_name) {
    *
    * @return \Drupal\Core\Field\FieldItemListInterface
    */
-  protected function getTranslatedField($property_name, $langcode) {
+  protected function getTranslatedField($name, $langcode) {
     if ($this->translations[$this->activeLangcode]['status'] == static::TRANSLATION_REMOVED) {
       $message = 'The entity object refers to a removed translation (@langcode) and cannot be manipulated.';
       throw new \InvalidArgumentException(format_string($message, array('@langcode' => $this->activeLangcode)));
     }
     // Populate $this->fields to speed-up further look-ups and to keep track of
     // fields objects, possibly holding changes to field values.
-    if (!isset($this->fields[$property_name][$langcode])) {
-      $definition = $this->getPropertyDefinition($property_name);
+    if (!isset($this->fields[$name][$langcode])) {
+      $definition = $this->getPropertyDefinition($name);
       if (!$definition) {
-        throw new \InvalidArgumentException('Field ' . check_plain($property_name) . ' is unknown.');
+        throw new \InvalidArgumentException('Field ' . check_plain($name) . ' is unknown.');
       }
       // Non-translatable fields are always stored with
       // Language::LANGCODE_DEFAULT as key.
-      if ($langcode != Language::LANGCODE_DEFAULT && empty($definition['translatable'])) {
-        if (!isset($this->fields[$property_name][Language::LANGCODE_DEFAULT])) {
-          $this->fields[$property_name][Language::LANGCODE_DEFAULT] = $this->getTranslatedField($property_name, Language::LANGCODE_DEFAULT);
+      $default = $langcode == Language::LANGCODE_DEFAULT;
+      if (!$default && empty($definition['translatable'])) {
+        if (!isset($this->fields[$name][Language::LANGCODE_DEFAULT])) {
+          $this->fields[$name][Language::LANGCODE_DEFAULT] = $this->getTranslatedField($name, Language::LANGCODE_DEFAULT);
         }
-        $this->fields[$property_name][$langcode] = &$this->fields[$property_name][Language::LANGCODE_DEFAULT];
+        $this->fields[$name][$langcode] = &$this->fields[$name][Language::LANGCODE_DEFAULT];
       }
       else {
         $value = NULL;
-        if (isset($this->values[$property_name][$langcode])) {
-          $value = $this->values[$property_name][$langcode];
+        if (isset($this->values[$name][$langcode])) {
+          $value = $this->values[$name][$langcode];
+        }
+        $field = \Drupal::typedData()->getPropertyInstance($this, $name, $value);
+        if ($default) {
+          // $this->defaultLangcode might not be set if we are initializing the
+          // default language code cache, in which case there is no valid
+          // langcode to assign.
+          $field_langcode = isset($this->defaultLangcode) ? $this->defaultLangcode : Language::LANGCODE_NOT_SPECIFIED;
+        }
+        else {
+          $field_langcode = $langcode;
         }
-        $field = \Drupal::typedData()->getPropertyInstance($this, $property_name, $value);
-        $field->setLangcode($langcode);
-        $this->fields[$property_name][$langcode] = $field;
+        $field->setLangcode($field_langcode);
+        $this->fields[$name][$langcode] = $field;
       }
     }
-    return $this->fields[$property_name][$langcode];
+    return $this->fields[$name][$langcode];
   }
 
   /**
    * {@inheritdoc}
    */
-  public function set($property_name, $value, $notify = TRUE) {
-    $this->get($property_name)->setValue($value, FALSE);
-
-    if ($property_name == 'langcode') {
-      // Avoid using unset as this unnecessarily triggers magic methods later
-      // on.
-      $this->language = NULL;
-    }
+  public function set($name, $value, $notify = TRUE) {
+    // If default language changes we need to react to that.
+    $notify = $name == 'langcode';
+    $this->get($name)->setValue($value, $notify);
   }
 
   /**
@@ -530,37 +536,50 @@ public function access($operation = 'view', AccountInterface $account = NULL) {
    * {@inheritdoc}
    */
   public function language() {
+    $language = NULL;
     if ($this->activeLangcode != Language::LANGCODE_DEFAULT) {
       if (!isset($this->languages[$this->activeLangcode])) {
         $this->languages += language_list(Language::STATE_ALL);
       }
-      return $this->languages[$this->activeLangcode];
+      $language = $this->languages[$this->activeLangcode];
     }
     else {
-      return $this->language ?: $this->getDefaultLanguage();
+      $language = $this->languages[$this->defaultLangcode];
     }
+    return $language;
   }
 
   /**
-   * Returns the entity original language.
+   * Populates the local cache for the default language code.
+   */
+  protected function setDefaultLangcode() {
+    // Get the language code if the property exists.
+    if ($this->getPropertyDefinition('langcode') && ($item = $this->get('langcode')) && isset($item->language)) {
+      $this->defaultLangcode = $item->language->id;
+    }
+    if (empty($this->defaultLangcode)) {
+      // Make sure we return a proper language object.
+      $this->defaultLangcode = Language::LANGCODE_NOT_SPECIFIED;
+    }
+    // This needs to be initialized manually as it is skipped when instantiating
+    // the language field object to avoid infinite recursion.
+    if (!empty($this->fields['langcode'])) {
+      $this->fields['langcode'][Language::LANGCODE_DEFAULT]->setLangcode($this->defaultLangcode);
+    }
+  }
+
+  /**
+   * Updates language for already instantiated fields.
    *
    * @return \Drupal\Core\Language\Language
    *   A language object.
    */
-  protected function getDefaultLanguage() {
-    // Keep a local cache of the language object and clear it if the langcode
-    // gets changed, see ContentEntityBase::onChange().
-    if (!isset($this->language)) {
-      // Get the language code if the property exists.
-      if ($this->getPropertyDefinition('langcode') && ($item = $this->get('langcode')) && isset($item->language)) {
-        $this->language = $item->language;
-      }
-      if (empty($this->language)) {
-        // Make sure we return a proper language object.
-        $this->language = new Language(array('id' => Language::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE));
+  protected function updateFieldLangcodes($langcode) {
+    foreach ($this->fields as $name => $items) {
+      if (!empty($items[Language::LANGCODE_DEFAULT])) {
+        $items[Language::LANGCODE_DEFAULT]->setLangcode($langcode);
       }
     }
-    return $this->language;
   }
 
   /**
@@ -570,7 +589,8 @@ public function onChange($property_name) {
     if ($property_name == 'langcode') {
       // Avoid using unset as this unnecessarily triggers magic methods later
       // on.
-      $this->language = NULL;
+      $this->setDefaultLangcode();
+      $this->updateFieldLangcodes($this->defaultLangcode);
     }
   }
 
@@ -582,11 +602,8 @@ public function onChange($property_name) {
   public function getTranslation($langcode) {
     // Ensure we always use the default language code when dealing with the
     // original entity language.
-    if ($langcode != Language::LANGCODE_DEFAULT) {
-      $default_language = $this->language ?: $this->getDefaultLanguage();
-      if ($langcode == $default_language->id) {
-        $langcode = Language::LANGCODE_DEFAULT;
-      }
+    if ($langcode != Language::LANGCODE_DEFAULT && $langcode == $this->defaultLangcode) {
+      $langcode = Language::LANGCODE_DEFAULT;
     }
 
     // Populate entity translation object cache so it will be available for all
@@ -608,12 +625,11 @@ public function getTranslation($langcode) {
       else {
         // If we were given a valid language and there is no translation for it,
         // we return a new one.
-        $languages = language_list(Language::STATE_ALL);
-        if (isset($languages[$langcode])) {
+        if (isset($this->languages[$langcode])) {
           // If the entity or the requested language  is not a configured
           // language, we fall back to the entity itself, since in this case it
           // cannot have translations.
-          $translation = empty($this->getDefaultLanguage()->locked) && empty($languages[$langcode]->locked) ? $this->addTranslation($langcode) : $this;
+          $translation = empty($this->languages[$this->defaultLangcode]->locked) && empty($this->languages[$langcode]->locked) ? $this->addTranslation($langcode) : $this;
         }
       }
     }
@@ -674,8 +690,7 @@ protected function initializeTranslation($langcode) {
    * {@inheritdoc}
    */
   public function hasTranslation($langcode) {
-    $default_language = $this->language ?: $this->getDefaultLanguage();
-    if ($langcode == $default_language->id) {
+    if ($langcode == $this->defaultLangcode) {
       $langcode = Language::LANGCODE_DEFAULT;
     }
     return !empty($this->translations[$langcode]['status']);
@@ -685,8 +700,7 @@ public function hasTranslation($langcode) {
    * {@inheritdoc}
    */
   public function addTranslation($langcode, array $values = array()) {
-    $languages = language_list(Language::STATE_ALL);
-    if (!isset($languages[$langcode]) || $this->hasTranslation($langcode)) {
+    if (!isset($this->languages[$langcode]) || $this->hasTranslation($langcode)) {
       $message = 'Invalid translation language (@langcode) specified.';
       throw new \InvalidArgumentException(format_string($message, array('@langcode' => $langcode)));
     }
@@ -722,7 +736,7 @@ public function addTranslation($langcode, array $values = array()) {
    * {@inheritdoc}
    */
   public function removeTranslation($langcode) {
-    if (isset($this->translations[$langcode]) && $langcode != Language::LANGCODE_DEFAULT && $langcode != $this->getDefaultLanguage()->id) {
+    if (isset($this->translations[$langcode]) && $langcode != Language::LANGCODE_DEFAULT && $langcode != $this->defaultLangcode) {
       foreach ($this->getPropertyDefinitions() as $name => $definition) {
         if (!empty($definition['translatable'])) {
           unset($this->values[$name][$langcode]);
@@ -741,7 +755,7 @@ public function removeTranslation($langcode) {
    * {@inheritdoc}
    */
   public function initTranslation($langcode) {
-    if ($langcode != Language::LANGCODE_DEFAULT && $langcode != $this->getDefaultLanguage()->id) {
+    if ($langcode != Language::LANGCODE_DEFAULT && $langcode != $this->defaultLangcode) {
       $this->translations[$langcode]['status'] = static::TRANSLATION_EXISTING;
     }
   }
@@ -754,12 +768,11 @@ public function getTranslationLanguages($include_default = TRUE) {
     unset($translations[Language::LANGCODE_DEFAULT]);
 
     if ($include_default) {
-      $langcode = $this->getDefaultLanguage()->id;
-      $translations[$langcode] = TRUE;
+      $translations[$this->defaultLangcode] = TRUE;
     }
 
     // Now load language objects based upon translation langcodes.
-    return array_intersect_key(language_list(Language::STATE_ALL), $translations);
+    return array_intersect_key($this->languages, $translations);
   }
 
   /**
@@ -911,14 +924,11 @@ public function __clone() {
         }
       }
 
-      // Ensure the translations array is actually cloned by removing the
-      // original reference and re-creating its values.
+      // Ensure the translations array is actually cloned by overwriting the
+      // original reference with one pointing to a copy of the array.
       $this->clearTranslationCache();
       $translations = $this->translations;
-      unset($this->translations);
-      // This will trigger the magic setter as the translations array is
-      // undefined now.
-      $this->translations = $translations;
+      $this->translations = &$translations;
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
index 5497efb..a4c2659 100644
--- a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
@@ -325,7 +325,7 @@ protected function attachPropertyData(array &$entities, $revision_id = FALSE) {
           // Get the revision IDs.
           $revision_ids = array();
           foreach ($entities as $values) {
-            $revision_ids[] = $values[$this->revisionKey];
+            $revision_ids[] = $values[$this->revisionKey][Language::LANGCODE_DEFAULT];
           }
           $query->condition($this->revisionKey, $revision_ids);
         }
@@ -849,14 +849,13 @@ protected function doLoadFieldItems($entities, $age) {
     }
 
     // Load field data.
-    $all_langcodes = array_keys(language_list());
+    $langcodes = array_keys(language_list(Language::STATE_ALL));
     foreach ($fields as $field_name => $field) {
       $table = $load_current ? static::_fieldTableName($field) : static::_fieldRevisionTableName($field);
 
-      // If the field is translatable ensure that only values having valid
-      // languages are retrieved. Since we are loading values for multiple
-      // entities, we cannot limit the query to the available translations.
-      $langcodes = $field->isFieldTranslatable() ? $all_langcodes : array(Language::LANGCODE_NOT_SPECIFIED);
+      // Ensure that only values having valid languages are retrieved. Since we
+      // are loading values for multiple entities, we cannot limit the query to
+      // the available translations.
       $results = $this->database->select($table, 't')
         ->fields('t')
         ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
@@ -867,23 +866,29 @@ protected function doLoadFieldItems($entities, $age) {
 
       $delta_count = array();
       foreach ($results as $row) {
-        if (!isset($delta_count[$row->entity_id][$row->langcode])) {
-          $delta_count[$row->entity_id][$row->langcode] = 0;
-        }
-
-        if ($field->getFieldCardinality() == FieldInterface::CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field->getFieldCardinality()) {
-          $item = array();
-          // For each column declared by the field, populate the item from the
-          // prefixed database column.
-          foreach ($field->getColumns() as $column => $attributes) {
-            $column_name = static::_fieldColumnName($field, $column);
-            // Unserialize the value if specified in the column schema.
-            $item[$column] = (!empty($attributes['serialize'])) ? unserialize($row->$column_name) : $row->$column_name;
+        // Ensure that records for non-translatable fields having invalid
+        // languages are skipped.
+        // @todo Remove BC support for 'und' untranslatable fields as soon as
+        //   can write a migration for them.
+        if ($field->isFieldTranslatable() || $row->langcode == Language::LANGCODE_NOT_SPECIFIED || $row->langcode == $entities[$row->entity_id]->getUntranslated()->language()->id) {
+          if (!isset($delta_count[$row->entity_id][$row->langcode])) {
+            $delta_count[$row->entity_id][$row->langcode] = 0;
           }
 
-          // Add the item to the field values for the entity.
-          $entities[$row->entity_id]->getTranslation($row->langcode)->{$field_name}[$delta_count[$row->entity_id][$row->langcode]] = $item;
-          $delta_count[$row->entity_id][$row->langcode]++;
+          if ($field->getFieldCardinality() == FieldInterface::CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field->getFieldCardinality()) {
+            $item = array();
+            // For each column declared by the field, populate the item from the
+            // prefixed database column.
+            foreach ($field->getColumns() as $column => $attributes) {
+              $column_name = static::_fieldColumnName($field, $column);
+              // Unserialize the value if specified in the column schema.
+              $item[$column] = (!empty($attributes['serialize'])) ? unserialize($row->$column_name) : $row->$column_name;
+            }
+
+            // Add the item to the field values for the entity.
+            $entities[$row->entity_id]->getTranslation($row->langcode)->{$field_name}[$delta_count[$row->entity_id][$row->langcode]] = $item;
+            $delta_count[$row->entity_id][$row->langcode]++;
+          }
         }
       }
     }
@@ -897,6 +902,9 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) {
     $id = $entity->id();
     $bundle = $entity->bundle();
     $entity_type = $entity->entityType();
+    $default_langcode = $entity->getUntranslated()->language()->id;
+    $translation_langcodes = array_keys($entity->getTranslationLanguages());
+
     if (!isset($vid)) {
       $vid = $id;
     }
@@ -930,7 +938,7 @@ protected function doSaveFieldItems(EntityInterface $entity, $update) {
       $query = $this->database->insert($table_name)->fields($columns);
       $revision_query = $this->database->insert($revision_name)->fields($columns);
 
-      $langcodes = $field->isFieldTranslatable() ? array_keys($entity->getTranslationLanguages()) : array(Language::LANGCODE_NOT_SPECIFIED);
+      $langcodes = $field->isFieldTranslatable() ? $translation_langcodes : array($default_langcode);
       foreach ($langcodes as $langcode) {
         $delta_count = 0;
         $items = $entity->getTranslation($langcode)->get($field_name);
diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php
index 00dcaba..da50ce1 100644
--- a/core/lib/Drupal/Core/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Field/FieldItemList.php
@@ -39,7 +39,7 @@ class FieldItemList extends ItemList implements FieldItemListInterface {
    *
    * @var string
    */
-  protected $langcode = Language::LANGCODE_DEFAULT;
+  protected $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
   /**
    * Overrides TypedData::__construct().
diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php
index b5ea710..825a638 100644
--- a/core/lib/Drupal/Core/Language/Language.php
+++ b/core/lib/Drupal/Core/Language/Language.php
@@ -60,10 +60,10 @@ class Language {
   /**
    * Language code referring to the default language of data, e.g. of an entity.
    *
-   * @todo: Change value to differ from Language::LANGCODE_NOT_SPECIFIED once
-   * field API leverages the property API.
+   * See the BCP 47 syntax to define private language tags:
+   * http://www.rfc-editor.org/rfc/bcp/bcp47.txt
    */
-  const LANGCODE_DEFAULT = 'und';
+  const LANGCODE_DEFAULT = 'x-default';
 
   /**
    * The language state when referring to configurable languages.
diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc
index 6d02b9d..4c767f0 100644
--- a/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -331,9 +331,6 @@ function content_translation_form_language_content_settings_submit(array $form,
  *     language_save_default_configuration().
  *   - fields: An associative array with field names as keys and a boolean as
  *     value, indicating field translatability.
- *
- * @todo Remove this migration entirely once the Field API is converted to the
- *   Entity Field API.
  */
 function _content_translation_update_field_translatability($settings) {
   $fields = array();
@@ -346,224 +343,15 @@ function _content_translation_update_field_translatability($settings) {
         foreach ($bundle_settings['fields'] as $field_name => $translatable) {
           // If a field is enabled for translation for at least one instance we
           // need to mark it as translatable.
-          if (FieldService::fieldInfo()->getField($entity_type, $field_name)) {
-            $fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]);
+          $field = FieldService::fieldInfo()->getField($entity_type, $field_name);
+          if ($field && $field->isFieldTranslatable() !== $translatable) {
+            $field->translatable = $translatable;
+            $field->save();
           }
         }
       }
     }
   }
 
-  $operations = array();
-  foreach ($fields as $entity_type => $entity_type_fields) {
-    foreach ($entity_type_fields as $field_name => $translatable) {
-      $field = field_info_field($entity_type, $field_name);
-      if ($field->isFieldTranslatable() != $translatable) {
-        // If a field is untranslatable, it can have no data except under
-        // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable before
-        // we convert data to the entity language. Conversely we need to switch
-        // data back to Language::LANGCODE_NOT_SPECIFIED before making a field
-        // untranslatable lest we lose information.
-        $field_operations = array(
-          array('content_translation_translatable_switch', array($translatable, $entity_type, $field_name)),
-        );
-        if ($field->hasData()) {
-          $field_operations[] = array('content_translation_translatable_batch', array($translatable, $field_name));
-          $field_operations = $translatable ? $field_operations : array_reverse($field_operations);
-        }
-        $operations = array_merge($operations, $field_operations);
-      }
-    }
-  }
-
-  // As last operation store the submitted settings.
-  $operations[] = array('content_translation_save_settings', array($settings));
-
-  $batch = array(
-    'title' => t('Updating translatability for the selected fields'),
-    'operations' => $operations,
-    'finished' => 'content_translation_translatable_batch_done',
-    'file' => drupal_get_path('module', 'content_translation') . '/content_translation.admin.inc',
-  );
-  batch_set($batch);
-}
-
-/**
- * Toggles translatability of the given field.
- *
- * This is called from a batch operation, but should only run once per field.
- *
- * @param bool $translatable
- *   Indicator of whether the field should be made translatable (TRUE) or
- *   untranslatble (FALSE).
- * @param string $entity_type
- *   Field entity type.
- * @param string $field_name
- *   Field machine name.
- */
-function content_translation_translatable_switch($translatable, $entity_type, $field_name) {
-  $field = field_info_field($entity_type, $field_name);
-  if ($field->isFieldTranslatable() !== $translatable) {
-    $field->translatable = $translatable;
-    $field->save();
-  }
+  content_translation_save_settings($settings);
 }
-
-/**
- * Batch callback: Converts field data to or from Language::LANGCODE_NOT_SPECIFIED.
- *
- * @param bool $translatable
- *   Indicator of whether the field should be made translatable (TRUE) or
- *   untranslatble (FALSE).
- * @param string $field_name
- *   Field machine name.
- */
-function content_translation_translatable_batch($translatable, $field_name, &$context) {
-  // Determine the entity types to act on.
-  $entity_types = array();
-  foreach (field_info_instances() as $entity_type => $info) {
-    foreach ($info as $bundle => $instances) {
-      foreach ($instances as $instance_field_name => $instance) {
-        if ($instance_field_name == $field_name) {
-          $entity_types[] = $entity_type;
-          break 2;
-        }
-      }
-    }
-  }
-
-  if (empty($context['sandbox'])) {
-    $context['sandbox']['progress'] = 0;
-    $context['sandbox']['max'] = 0;
-
-    foreach ($entity_types as $entity_type) {
-      $field = field_info_field($entity_type, $field_name);
-      $columns = $field->getColumns();
-      $column = isset($columns['value']) ? 'value' : key($columns);
-      $query_field = "$field_name.$column";
-
-      // How many entities will need processing?
-      $query = \Drupal::entityQuery($entity_type);
-      $count = $query
-        ->exists($query_field)
-        ->count()
-        ->execute();
-
-      $context['sandbox']['max'] += $count;
-      $context['sandbox']['progress_entity_type'][$entity_type] = 0;
-      $context['sandbox']['max_entity_type'][$entity_type] = $count;
-    }
-
-    if ($context['sandbox']['max'] === 0) {
-      // Nothing to do.
-      $context['finished'] = 1;
-      return;
-    }
-  }
-
-  foreach ($entity_types as $entity_type) {
-    if ($context['sandbox']['max_entity_type'][$entity_type] === 0) {
-      continue;
-    }
-
-    $info = entity_get_info($entity_type);
-    $offset = $context['sandbox']['progress_entity_type'][$entity_type];
-    $query = \Drupal::entityQuery($entity_type);
-    $field = field_info_field($entity_type, $field_name);
-    $columns = $field->getColumns();
-    $column = isset($columns['value']) ? 'value' : key($columns);
-    $query_field = "$field_name.$column";
-    $result = $query
-      ->exists($query_field)
-      ->sort($info['entity_keys']['id'])
-      ->range($offset, 10)
-      ->execute();
-
-    foreach (entity_load_multiple($entity_type, $result) as $id => $entity) {
-      $context['sandbox']['max_entity_type'][$entity_type] -= count($result);
-      $context['sandbox']['progress_entity_type'][$entity_type]++;
-      $context['sandbox']['progress']++;
-      $langcode = $entity->language()->id;
-
-      // Skip process for language neutral entities.
-      if ($langcode == Language::LANGCODE_NOT_SPECIFIED) {
-        continue;
-      }
-
-      // We need a two-step approach while updating field translations: given
-      // that field-specific update functions might rely on the stored values to
-      // perform their processing first we need to store the new translations
-      // and only after we can remove the old ones. Otherwise we might have data
-      // loss, since the removal of the old translations might occur before the
-      // new ones are stored.
-      if ($translatable && isset($entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED])) {
-        // If the field is being switched to translatable and has data for
-        // Language::LANGCODE_NOT_SPECIFIED then we need to move the data to the right
-        // language.
-        $entity->{$field_name}[$langcode] = $entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED];
-        // Store the original value.
-        _content_translation_update_field($entity_type, $entity, $field_name);
-        $entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED] = array();
-        // Remove the language neutral value.
-        _content_translation_update_field($entity_type, $entity, $field_name);
-      }
-      elseif (!$translatable && isset($entity->{$field_name}[$langcode])) {
-        // The field has been marked untranslatable and has data in the entity
-        // language: we need to move it to Language::LANGCODE_NOT_SPECIFIED and drop the
-        // other translations.
-        $entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED] = $entity->{$field_name}[$langcode];
-        // Store the original value.
-        _content_translation_update_field($entity_type, $entity, $field_name);
-        // Remove translations.
-        foreach ($entity->{$field_name} as $langcode => $items) {
-          if ($langcode != Language::LANGCODE_NOT_SPECIFIED) {
-            $entity->{$field_name}[$langcode] = array();
-          }
-        }
-        _content_translation_update_field($entity_type, $entity, $field_name);
-      }
-      else {
-        // No need to save unchanged entities.
-        continue;
-      }
-    }
-  }
-
-  $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
-}
-
-/**
- * Stores the given field translations.
- */
-function _content_translation_update_field($entity_type, EntityInterface $entity, $field_name) {
-  $empty = 0;
-  $translations = $entity->getTranslationLanguages();
-
-  // Ensure that we are trying to store only valid data.
-  foreach (array_keys($translations) as $langcode) {
-    $items = $entity->getTranslation($langcode)->get($field_name);
-    $items->filterEmptyValues();
-    $empty += $items->isEmpty();
-  }
-
-  // Save the field value only if there is at least one item available,
-  // otherwise any stored empty field value would be deleted. If this happens
-  // the range queries would be messed up.
-  if ($empty < count($translations)) {
-    $entity->save();
-  }
-}
-
-/**
- * Batch finished callback: Checks the exit status of the batch operation.
- */
-function content_translation_translatable_batch_done($success, $results, $operations) {
-  if ($success) {
-    drupal_set_message(t("Successfully changed field translation setting."));
-  }
-  else {
-    // @todo: Do something about this case.
-    drupal_set_message(t("Something went wrong while processing data. Some nodes may appear to have lost fields."), 'error');
-  }
-}
-
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 43127b0..747ce68 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -79,10 +79,6 @@ function content_translation_entity_info_alter(array &$entity_info) {
   // Provide defaults for translation info.
   foreach ($entity_info as $entity_type => &$info) {
     if (!empty($info['translatable'])) {
-      // Every fieldable entity type must have a translation controller class,
-      // no matter if it is enabled for translation or not. As a matter of fact
-      // we might need it to correctly switch field translatability when a field
-      // is shared accross different entities.
       $info['controllers'] += array('translation' => 'Drupal\content_translation\ContentTranslationController');
 
       if (!isset($info['translation']['content_translation'])) {
@@ -207,12 +203,6 @@ function content_translation_menu() {
     }
   }
 
-  $items['admin/config/regional/content_translation/translatable/%/%'] = array(
-    'title' => 'Confirm change in translatability.',
-    'description' => 'Confirm page for changing field translatability.',
-    'route_name' => 'content_translation.translatable',
-  );
-
   return $items;
 }
 
@@ -801,36 +791,12 @@ function content_translation_field_extra_fields() {
  * Implements hook_form_FORM_ID_alter() for 'field_ui_field_edit_form'.
  */
 function content_translation_form_field_ui_field_edit_form_alter(array &$form, array &$form_state, $form_id) {
-  $field = $form['#field'];
-  $field_name = $field->getFieldName();
-  $translatable = $field->isFieldTranslatable();
-  $entity_type = $field->entity_type;
-  $label = t('Field translation');
-
-  if ($field->hasData()) {
-    $form['field']['translatable'] = array(
-      '#type' => 'item',
-      '#title' => $label,
-      '#attributes' => array('class' => 'translatable'),
-      'link' => array(
-        '#type' => 'link',
-        '#prefix' => t('This field has data in existing content.') . ' ',
-        '#title' => !$translatable ? t('Enable translation') : t('Disable translation'),
-        '#href' => "admin/config/regional/content_translation/translatable/$entity_type/$field_name",
-        '#options' => array('query' => drupal_get_destination()),
-        '#access' => user_access('administer content translation'),
-      ),
-    );
-  }
-  else {
-    $form['field']['translatable'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Users may translate this field.'),
-      '#default_value' => $translatable,
-    );
-  }
-
-  $form['field']['translatable']['#weight'] = 20;
+  $form['field']['translatable'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Users may translate this field.'),
+    '#default_value' => $form['#field']->isFieldTranslatable(),
+    '#weight' => 20,
+  );
 }
 
 /**
diff --git a/core/modules/content_translation/content_translation.routing.yml b/core/modules/content_translation/content_translation.routing.yml
deleted file mode 100644
index 51db4a3..0000000
--- a/core/modules/content_translation/content_translation.routing.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-content_translation.translatable:
-  path: '/admin/config/regional/content_translation/translatable/{entity_type}/{field_name}'
-  defaults:
-    _form: 'Drupal\content_translation\Form\TranslatableForm'
-  requirements:
-    _permission: 'administer content translation'
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php b/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php
deleted file mode 100644
index 363cb1c..0000000
--- a/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php
+++ /dev/null
@@ -1,156 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\content_translation\Form\TranslatableForm.
- */
-
-namespace Drupal\content_translation\Form;
-
-use Drupal\Core\Form\ConfirmFormBase;
-use Drupal\field\Entity\Field;
-use Drupal\field\Field as FieldInfo;
-
-/**
- * Provides a confirm form for changing translatable status on translation
- * fields.
- */
-class TranslatableForm extends ConfirmFormBase {
-
-  /**
-   * The field info we are changing translatable status on.
-   *
-   * @var \Drupal\field\Entity\Field
-   */
-  protected $field;
-
-  /**
-   * The field name we are changing translatable
-   * status on.
-   *
-   * @var string.
-   */
-  protected $fieldName;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'content_translation_translatable_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    if ($this->field->isFieldTranslatable()) {
-      $question = t('Are you sure you want to disable translation for the %name field?', array('%name' => $this->fieldName));
-    }
-    else {
-      $question = t('Are you sure you want to enable translation for the %name field?', array('%name' => $this->fieldName));
-    }
-    return $question;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDescription() {
-    $description = t('By submitting this form these changes will apply to the %name field everywhere it is used.',
-      array('%name' => $this->fieldName)
-    );
-    $description .= $this->field->isFieldTranslatable() ? "<br>" . t("<strong>All the existing translations of this field will be deleted.</strong><br>This action cannot be undone.") : '';
-    return $description;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelRoute() {
-    return array(
-      'route_name' => '<front>',
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   * @param string $entity_type
-   *   The entity type.
-   * @param string $field_name
-   *   The field name.
-   */
-  public function buildForm(array $form, array &$form_state, $entity_type = NULL, $field_name = NULL) {
-    $this->fieldName = $field_name;
-    $this->fieldInfo = FieldInfo::fieldInfo()->getField($entity_type, $field_name);
-
-    return parent::buildForm($form, $form_state);
-  }
-
-  /**
-   * Form submission handler.
-   *
-   * This submit handler maintains consistency between the translatability of an
-   * entity and the language under which the field data is stored. When a field
-   * is marked as translatable, all the data in
-   * $entity->{field_name}[Language::LANGCODE_NOT_SPECIFIED] is moved to
-   * $entity->{field_name}[$entity_language]. When a field is marked as
-   * untranslatable the opposite process occurs. Note that marking a field as
-   * untranslatable will cause all of its translations to be permanently
-   * removed, with the exception of the one corresponding to the entity
-   * language.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
-   */
-  public function submitForm(array &$form, array &$form_state) {
-    // This is the current state that we want to reverse.
-    $translatable = $form_state['values']['translatable'];
-    if ($this->field->translatable !== $translatable) {
-      // Field translatability has changed since form creation, abort.
-      $t_args = array('%field_name');
-      $msg = $translatable ?
-        t('The field %field_name is already translatable. No change was performed.', $t_args):
-        t('The field %field_name is already untranslatable. No change was performed.', $t_args);
-      drupal_set_message($msg, 'warning');
-      return;
-    }
-
-    // If a field is untranslatable, it can have no data except under
-    // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable
-    // before we convert data to the entity language. Conversely we need to
-    // switch data back to Language::LANGCODE_NOT_SPECIFIED before making a
-    // field untranslatable lest we lose information.
-    $operations = array(
-      array(
-        'content_translation_translatable_batch', array(
-          !$translatable,
-          $this->fieldName,
-        ),
-      ),
-      array(
-        'content_translation_translatable_switch', array(
-          !$translatable,
-          $this->field['entity_type'],
-          $this->fieldName,
-        ),
-      ),
-    );
-    $operations = $translatable ? $operations : array_reverse($operations);
-
-    $t_args = array('%field' => $this->fieldName);
-    $title = !$translatable ? t('Enabling translation for the %field field', $t_args) : t('Disabling translation for the %field field', $t_args);
-
-    $batch = array(
-      'title' => $title,
-      'operations' => $operations,
-      'finished' => 'content_translation_translatable_batch_done',
-      'file' => drupal_get_path('module', 'content_translation') . '/content_translation.admin.inc',
-    );
-
-    batch_set($batch);
-
-  }
-
-}
diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc
index 68493c7..2ea2bf1 100644
--- a/core/modules/field/field.multilingual.inc
+++ b/core/modules/field/field.multilingual.inc
@@ -21,11 +21,11 @@
  * @endcode
  * Every field can hold a single or multiple value for each language code
  * belonging to the available language codes set:
- * - For untranslatable fields this set only contains Language::LANGCODE_NOT_SPECIFIED.
+ * - For untranslatable fields this set is only Language::LANGCODE_DEFAULT.
  * - For translatable fields this set can contain any language code. By default
  *   it is the list returned by field_content_languages(), which contains all
- *   installed languages with the addition of Language::LANGCODE_NOT_SPECIFIED. This
- *   default can be altered by modules implementing
+ *   installed languages with the addition of Language::LANGCODE_NOT_SPECIFIED.
+ *   This default can be altered by modules implementing
  *   hook_field_available_languages_alter().
  *
  * The available language codes for a particular field are returned by
@@ -69,10 +69,10 @@
  * Collects the available language codes for the given entity type and field.
  *
  * If the given field has language support enabled, an array of available
- * language codes will be returned, otherwise only Language::LANGCODE_NOT_SPECIFIED will
- * be returned. Since the default value for a 'translatable' entity property is
- * FALSE, we ensure that only entities that are able to handle translations
- * actually get translatable fields.
+ * language codes will be returned, otherwise only Language::LANGCODE_DEFAULT
+ * will be returned. Since the default value for a 'translatable' entity
+ * property is FALSE, we ensure that only entities that are able to handle
+ * translations actually get translatable fields.
  *
  * @param $entity_type
  *   The type of the entity the field is attached to, e.g. 'node' or 'user'.
@@ -92,7 +92,7 @@ function field_available_languages($entity_type, FieldInterface $field) {
 
   if (!isset($field_langcodes[$entity_type][$field_name])) {
     // If the field has language support enabled we retrieve an (alterable) list
-    // of enabled languages, otherwise we return just Language::LANGCODE_NOT_SPECIFIED.
+    // of enabled languages, otherwise we return Language::LANGCODE_DEFAULT.
     if (field_is_translatable($entity_type, $field)) {
       $langcodes = field_content_languages();
       // Let other modules alter the available languages.
@@ -101,7 +101,7 @@ function field_available_languages($entity_type, FieldInterface $field) {
       $field_langcodes[$entity_type][$field_name] = $langcodes;
     }
     else {
-      $field_langcodes[$entity_type][$field_name] = array(Language::LANGCODE_NOT_SPECIFIED);
+      $field_langcodes[$entity_type][$field_name] = array(Language::LANGCODE_DEFAULT);
     }
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
index de2dd94..0c02b4f 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
@@ -142,7 +142,7 @@ function testFieldAvailableLanguages() {
     $this->field->translatable = FALSE;
     $this->field->save();
     $available_langcodes = field_available_languages($this->entity_type, $this->field);
-    $this->assertTrue(count($available_langcodes) == 1 && $available_langcodes[0] === Language::LANGCODE_NOT_SPECIFIED, 'For untranslatable fields only Language::LANGCODE_NOT_SPECIFIED is available.');
+    $this->assertTrue(count($available_langcodes) == 1 && $available_langcodes[0] === Language::LANGCODE_DEFAULT, 'For untranslatable fields only Language::LANGCODE_DEFAULT is available.');
   }
 
   /**
diff --git a/core/modules/hal/lib/Drupal/hal/Tests/DenormalizeTest.php b/core/modules/hal/lib/Drupal/hal/Tests/DenormalizeTest.php
index 910c14f..32bc279 100644
--- a/core/modules/hal/lib/Drupal/hal/Tests/DenormalizeTest.php
+++ b/core/modules/hal/lib/Drupal/hal/Tests/DenormalizeTest.php
@@ -206,7 +206,10 @@ public function testPatchDenormailzation() {
     // Assert that all fields are NULL and not set to default values. Example:
     // the UUID field is NULL and not initialized as usual.
     foreach ($denormalized as $field_name => $field) {
-      $this->assertFalse(isset($denormalized->$field_name), "$field_name is not set.");
+      // The 'langcode' field always has a value.
+      if ($field_name != 'langcode') {
+        $this->assertFalse(isset($denormalized->$field_name), "$field_name is not set.");
+      }
     }
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
index bc0e195..eabcdeb 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
@@ -7,10 +7,13 @@
 
 namespace Drupal\system\Tests\Entity;
 
+use Drupal\Component\Utility\MapArray;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\entity_test\Entity\EntityTestMulRev;
-use Drupal\Component\Utility\MapArray;
+use Drupal\field\Field as FieldService;
 
 /**
  * Tests entity translation.
@@ -19,6 +22,20 @@ class EntityTranslationTest extends EntityUnitTestBase {
 
   protected $langcodes;
 
+  /**
+   * The test field name.
+   *
+   * @var string
+   */
+  protected $field_name;
+
+  /**
+   * The untranslatable test field name.
+   *
+   * @var string
+   */
+  protected $untranslatable_field_name;
+
   public static $modules = array('language', 'entity_test');
 
   public static function getInfo() {
@@ -54,7 +71,10 @@ function setUp() {
     // Create a translatable test field.
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
 
-    // Create instance in all entity variations.
+    // Create an untranslatable test field.
+    $this->untranslatable_field_name = drupal_strtolower($this->randomName() . '_field_name');
+
+    // Create field instances in all entity variations.
     foreach (entity_test_entity_types() as $entity_type) {
       entity_create('field_entity', array(
         'name' => $this->field_name,
@@ -69,6 +89,19 @@ function setUp() {
         'bundle' => $entity_type,
       ))->save();
       $this->instance[$entity_type] = field_read_instance($entity_type, $this->field_name, $entity_type);
+
+      entity_create('field_entity', array(
+        'name' => $this->untranslatable_field_name,
+        'entity_type' => $entity_type,
+        'type' => 'text',
+        'cardinality' => 4,
+        'translatable' => FALSE,
+      ))->save();
+      entity_create('field_instance', array(
+        'field_name' => $this->untranslatable_field_name,
+        'entity_type' => $entity_type,
+        'bundle' => $entity_type,
+      ))->save();
     }
 
     // Create the default languages.
@@ -120,7 +153,7 @@ protected function _testEntityLanguageMethods($entity_type) {
     // Get the value.
     $field = $entity->getTranslation(Language::LANGCODE_DEFAULT)->get($this->field_name);
     $this->assertEqual($field->value, 'default value', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
 
     // Set the value in a certain language. As the entity is not
     // language-specific it should use the default language and so ignore the
@@ -133,11 +166,12 @@ protected function _testEntityLanguageMethods($entity_type) {
     // language-specific entity.
     $field = $entity->getTranslation($this->langcodes[1])->get($this->field_name);
     $this->assertEqual($field->value, 'default value2', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
 
     // Now, make the entity language-specific by assigning a language and test
     // translating it.
-    $entity->langcode->value = $this->langcodes[0];
+    $default_langcode = $this->langcodes[0];
+    $entity->langcode->value = $default_langcode;
     $entity->{$this->field_name} = array();
     $this->assertEqual($entity->language(), language_load($this->langcodes[0]), format_string('%entity_type: Entity language retrieved.', array('%entity_type' => $entity_type)));
     $this->assertFalse($entity->getTranslationLanguages(FALSE), format_string('%entity_type: No translations are available', array('%entity_type' => $entity_type)));
@@ -147,7 +181,7 @@ protected function _testEntityLanguageMethods($entity_type) {
     // Get the value.
     $field = $entity->get($this->field_name);
     $this->assertEqual($field->value, 'default value', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($field->getLangcode(), $default_langcode, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
 
     // Set a translation.
     $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'translation 1')));
@@ -158,7 +192,7 @@ protected function _testEntityLanguageMethods($entity_type) {
     // Make sure the untranslated value stays.
     $field = $entity->get($this->field_name);
     $this->assertEqual($field->value, 'default value', 'Untranslated value stays.');
-    $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, 'Untranslated value has the expected langcode.');
+    $this->assertEqual($field->getLangcode(), $default_langcode, 'Untranslated value has the expected langcode.');
 
     $translations[$this->langcodes[1]] = language_load($this->langcodes[1]);
     $this->assertEqual($entity->getTranslationLanguages(FALSE), $translations, 'Translations retrieved.');
@@ -190,7 +224,7 @@ protected function _testEntityLanguageMethods($entity_type) {
     // Get the value.
     $field = $entity->get($field_name);
     $this->assertEqual($field->value, 'default value2', format_string('%entity_type: Untranslated value set into a translation in non-strict mode.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($field->getLangcode(), $default_langcode, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type)));
   }
 
   /**
@@ -219,20 +253,19 @@ protected function _testMultilingualProperties($entity_type) {
     $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid));
     $entity->save();
     $entity = entity_load($entity_type, $entity->id());
-    $this->assertEqual($entity->language()->id, Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Entity created as language neutral.', array('%entity_type' => $entity_type)));
+    $default_langcode = $entity->language()->id;
+    $this->assertEqual($default_langcode, Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Entity created as language neutral.', array('%entity_type' => $entity_type)));
     $field = $entity->getTranslation(Language::LANGCODE_DEFAULT)->get('name');
     $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name has been correctly stored as language neutral.', array('%entity_type' => $entity_type)));
-    $this->assertEqual(Language::LANGCODE_DEFAULT, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
     $this->assertEqual($uid, $entity->getTranslation(Language::LANGCODE_DEFAULT)->get('user_id')->target_id, format_string('%entity_type: The entity author has been correctly stored as language neutral.', array('%entity_type' => $entity_type)));
-    // As fields, translatable properties should ignore the given langcode and
-    // use neutral language if the entity is not translatable.
     $field = $entity->getTranslation($langcode)->get('name');
     $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name defaults to neutral language.', array('%entity_type' => $entity_type)));
-    $this->assertEqual(Language::LANGCODE_DEFAULT, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
     $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->target_id, format_string('%entity_type: The entity author defaults to neutral language.', array('%entity_type' => $entity_type)));
     $field = $entity->get('name');
     $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
-    $this->assertEqual(Language::LANGCODE_DEFAULT, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
     $this->assertEqual($uid, $entity->get('user_id')->target_id, format_string('%entity_type: The entity author can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
 
     // Create a language-aware entity and check that properties are stored
@@ -240,20 +273,21 @@ protected function _testMultilingualProperties($entity_type) {
     $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid, 'langcode' => $langcode));
     $entity->save();
     $entity = entity_load($entity_type, $entity->id());
-    $this->assertEqual($entity->language()->id, $langcode, format_string('%entity_type: Entity created as language specific.', array('%entity_type' => $entity_type)));
+    $default_langcode = $entity->language()->id;
+    $this->assertEqual($default_langcode, $langcode, format_string('%entity_type: Entity created as language specific.', array('%entity_type' => $entity_type)));
     $field = $entity->getTranslation($langcode)->get('name');
     $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name has been correctly stored as a language-aware property.', array('%entity_type' => $entity_type)));
-    $this->assertEqual(Language::LANGCODE_NOT_SPECIFIED, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
     $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->target_id, format_string('%entity_type: The entity author has been correctly stored as a language-aware property.', array('%entity_type' => $entity_type)));
     // Translatable properties on a translatable entity should use default
     // language if Language::LANGCODE_NOT_SPECIFIED is passed.
     $field = $entity->getTranslation(Language::LANGCODE_NOT_SPECIFIED)->get('name');
     $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name defaults to the default language.', array('%entity_type' => $entity_type)));
-    $this->assertEqual(Language::LANGCODE_NOT_SPECIFIED, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
     $this->assertEqual($uid, $entity->getTranslation(Language::LANGCODE_NOT_SPECIFIED)->get('user_id')->target_id, format_string('%entity_type: The entity author defaults to the default language.', array('%entity_type' => $entity_type)));
     $field = $entity->get('name');
     $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
-    $this->assertEqual(Language::LANGCODE_NOT_SPECIFIED, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type)));
     $this->assertEqual($uid, $entity->get('user_id')->target_id, format_string('%entity_type: The entity author can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
 
     // Create property translations.
@@ -285,8 +319,7 @@ protected function _testMultilingualProperties($entity_type) {
       );
       $field = $entity->getTranslation($langcode)->get('name');
       $this->assertEqual($properties[$langcode]['name'][0], $field->value, format_string('%entity_type: The entity name has been correctly stored for language %langcode.', $args));
-      // Fields for the default entity langcode are seen as language neutral.
-      $field_langcode = ($langcode == $entity->language()->id) ? Language::LANGCODE_NOT_SPECIFIED : $langcode;
+      $field_langcode = ($langcode == $entity->language()->id) ? $default_langcode : $langcode;
       $this->assertEqual($field_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expected langcode  %langcode.', $args));
       $this->assertEqual($properties[$langcode]['user_id'][0], $entity->getTranslation($langcode)->get('user_id')->target_id, format_string('%entity_type: The entity author has been correctly stored for language %langcode.', $args));
     }
@@ -482,6 +515,9 @@ function testEntityTranslationAPI() {
     $cloned = clone $entity;
     $translation = $cloned->getTranslation($langcode);
     $this->assertNotIdentical($entity, $translation->getUntranslated(), 'A cloned entity object has no reference to the original one.');
+    $entity->removeTranslation($langcode);
+    $this->assertFalse($entity->hasTranslation($langcode));
+    $this->assertTrue($cloned->hasTranslation($langcode));
 
     // Check that per-language defaults are properly populated.
     $entity = $this->reloadEntity($entity);
@@ -596,4 +632,152 @@ function testFieldDefinitions() {
     }
   }
 
+  /**
+   * Tests that changing entity language does not break field language.
+   */
+  public function testLanguageChange() {
+    $entity_type = 'entity_test_mul';
+    $controller = $this->entityManager->getStorageController($entity_type);
+    $langcode = $this->langcodes[0];
+
+    // check that field languages match entity language regardless of field
+    // translatability.
+    $values = array(
+      'langcode' => $langcode,
+      $this->field_name => $this->randomName(),
+      $this->untranslatable_field_name => $this->randomName(),
+    );
+    $entity = $controller->create($values);
+    foreach (array($this->field_name, $this->untranslatable_field_name) as $field_name) {
+      $this->assertEqual($entity->get($field_name)->getLangcode(), $langcode, 'Field language works as expected.');
+    }
+
+    // Check that field languages keep matching entity language even after
+    // changing it.
+    $langcode = $this->langcodes[1];
+    $entity->langcode->value = $langcode;
+    foreach (array($this->field_name, $this->untranslatable_field_name) as $field_name) {
+      $this->assertEqual($entity->get($field_name)->getLangcode(), $langcode, 'Field language works as expected after changing entity language.');
+    }
+
+    // Check that entity translation does not affect the language of original
+    // field values and untranslatable ones.
+    $langcode = $this->langcodes[0];
+    $entity->addTranslation($this->langcodes[2], array($this->field_name => $this->randomName()));
+    $entity->langcode->value = $langcode;
+    foreach (array($this->field_name, $this->untranslatable_field_name) as $field_name) {
+      $this->assertEqual($entity->get($field_name)->getLangcode(), $langcode, 'Field language works as expected after translating the entity and changing language.');
+    }
+  }
+
+  /**
+   * Tests field SQL storage.
+   */
+  public function testFieldSqlStorage() {
+    $entity_type = 'entity_test_mul';
+
+    $controller = $this->entityManager->getStorageController($entity_type);
+    $values = array(
+      $this->field_name => $this->randomName(),
+      $this->untranslatable_field_name => $this->randomName(),
+    );
+    $entity = $controller->create($values);
+    $entity->save();
+
+    // Tests that when changing language field language codes are still correct.
+    $langcode = $this->langcodes[0];
+    $entity->langcode->value = $langcode;
+    $entity->save();
+    $this->assertFieldStorageLangcode($entity, 'Field language successfully changed from language neutral.');
+    $langcode = $this->langcodes[1];
+    $entity->langcode->value = $langcode;
+    $entity->save();
+    $this->assertFieldStorageLangcode($entity, 'Field language successfully changed.');
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+    $entity->langcode->value = $langcode;
+    $entity->save();
+    $this->assertFieldStorageLangcode($entity, 'Field language successfully changed to language neutral.');
+
+    // Test that after switching field translatability things keep working as
+    // before.
+    $this->toggleFieldTranslatability($entity_type);
+    $entity = $this->reloadEntity($entity);
+    foreach (array($this->field_name, $this->untranslatable_field_name) as $field_name) {
+      $this->assertEqual($entity->get($field_name)->value, $values[$field_name], 'Field language works as expected after switching translatability.');
+    }
+
+    // Test that after disabling field translatability translated values are not
+    // loaded.
+    $this->toggleFieldTranslatability($entity_type);
+    $entity = $this->reloadEntity($entity);
+    $entity->langcode->value = $this->langcodes[0];
+    $translation = $entity->addTranslation($this->langcodes[1]);
+    $translated_value = $this->randomName();
+    $translation->get($this->field_name)->value = $translated_value;
+    $translation->save();
+    $this->toggleFieldTranslatability($entity_type);
+    $entity = $this->reloadEntity($entity);
+    $this->assertEqual($entity->getTranslation($this->langcodes[1])->get($this->field_name)->value, $values[$this->field_name], 'Existing field translations are not loaded for untranslatable fields.');
+  }
+
+  /**
+   * Checks whether field languages are correctly stored for the given entity.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity fields are attached to.
+   * @param string $message
+   *   (optional) A message to display with the assertion.
+   */
+  protected function assertFieldStorageLangcode(ContentEntityInterface $entity, $message = '') {
+    $status = TRUE;
+    $entity_type = $entity->entityType();
+    $id = $entity->id();
+    $langcode = $entity->getUntranslated()->language()->id;
+    $fields = array($this->field_name, $this->untranslatable_field_name);
+
+    foreach ($fields as $field_name) {
+      $field = FieldService::fieldInfo()->getField($entity_type, $field_name);
+      $tables = array(
+        FieldableDatabaseStorageController::_fieldTableName($field),
+        FieldableDatabaseStorageController::_fieldRevisionTableName($field),
+      );
+
+      foreach ($tables as $table) {
+        $record = \Drupal::database()
+          ->select($table, 'f')
+          ->fields('f')
+          ->condition('f.entity_id', $id)
+          ->condition('f.revision_id', $id)
+          ->execute()
+          ->fetchObject();
+
+        if ($record->langcode != $langcode) {
+          $status = FALSE;
+          break;
+        }
+      }
+    }
+
+    return $this->assertTrue($status, $message);
+  }
+
+  /**
+   * Toggles field translatability.
+   *
+   * @param string $entity_type
+   *   The type of the entity fields are attached to.
+   */
+  protected function toggleFieldTranslatability($entity_type) {
+    $fields = array($this->field_name, $this->untranslatable_field_name);
+    foreach ($fields as $field_name) {
+      $field = FieldService::fieldInfo()->getField($entity_type, $field_name);
+      $translatable = !$field->isFieldTranslatable();
+      $field->set('translatable', $translatable);
+      $field->save();
+      FieldService::fieldInfo()->flush();
+      $field = FieldService::fieldInfo()->getField($entity_type, $field_name);
+      $this->assertEqual($field->isFieldTranslatable(), $translatable, 'Field translatability changed.');
+    }
+    \Drupal::cache('field')->deleteAll();
+  }
 }
diff --git a/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php b/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php
index 0b47055..49d9f78 100644
--- a/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php
@@ -128,7 +128,7 @@ function testProcessedCache() {
     $entity = entity_load($entity_type, $entity->id());
     $cache = cache('field')->get("field:$entity_type:" . $entity->id());
     $this->assertEqual($cache->data, array(
-      Language::LANGCODE_DEFAULT => array(
+      Language::LANGCODE_NOT_SPECIFIED => array(
         'summary_field' => array(
           0 => array(
             'value' => $value,
@@ -144,7 +144,7 @@ function testProcessedCache() {
     // Inject fake processed values into the cache to make sure that these are
     // used as-is and not re-calculated when the entity is loaded.
     $data = array(
-      Language::LANGCODE_DEFAULT => array(
+      Language::LANGCODE_NOT_SPECIFIED => array(
         'summary_field' => array(
           0 => array(
             'value' => $value,
