diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index a11d560..55693b3 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -82,6 +82,13 @@
   protected $langcodeKey;
 
   /**
+   * The default langcode entity key.
+   *
+   * @var string
+   */
+  protected $defaultLangcodeKey;
+
+  /**
    * Language code identifying the entity active language.
    *
    * This is the language field accessors will use to determine which field
@@ -144,6 +151,7 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans
     $this->entityTypeId = $entity_type;
     $this->entityKeys['bundle'] = $bundle ? $bundle : $this->entityTypeId;
     $this->langcodeKey = $this->getEntityType()->getKey('langcode');
+    $this->defaultLangcodeKey = $this->getEntityType()->getKey('default_langcode');
 
     foreach ($values as $key => $value) {
       // If the key matches an existing property set the value to the property
@@ -245,6 +253,13 @@ public function isDefaultRevision($new_value = NULL) {
   /**
    * {@inheritdoc}
    */
+  public function isDefaultTranslation() {
+    return $this->activeLangcode === LanguageInterface::LANGCODE_DEFAULT;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getRevisionId() {
     return $this->getEntityKey('revision');
   }
@@ -543,14 +558,38 @@ public function onChange($name) {
       }
     }
 
-    // Update the default internal language cache.
-    if ($name == $this->langcodeKey) {
-      $this->setDefaultLangcode();
-      if (isset($this->translations[$this->defaultLangcode])) {
-        $message = String::format('A translation already exists for the specified language (@langcode).', array('@langcode' => $this->defaultLangcode));
-        throw new \InvalidArgumentException($message);
-      }
-      $this->updateFieldLangcodes($this->defaultLangcode);
+    switch ($name) {
+      case $this->langcodeKey:
+        if ($this->isDefaultTranslation()) {
+          // Update the default internal language cache.
+          $this->setDefaultLangcode();
+          if (isset($this->translations[$this->defaultLangcode])) {
+            $message = String::format('A translation already exists for the specified language (@langcode).', array('@langcode' => $this->defaultLangcode));
+            throw new \InvalidArgumentException($message);
+          }
+          $this->updateFieldLangcodes($this->defaultLangcode);
+        }
+        else {
+          // @todo Allow the translation language to be changed. See
+          //   https://www.drupal.org/node/2443989.
+          $items = $this->get($this->langcodeKey);
+          if ($items->value != $this->activeLangcode) {
+            $items->setValue($this->activeLangcode, FALSE);
+            $message = String::format('The translation language cannot be changed (@langcode).', array('@langcode' => $this->activeLangcode));
+            throw new \LogicException($message);
+          }
+        }
+        break;
+
+      case $this->defaultLangcodeKey:
+        // @todo Use a standard method to make the default_langcode field
+        //   read-only. See https://www.drupal.org/node/2443991.
+        if (isset($this->values[$this->defaultLangcodeKey])) {
+          $this->get($this->defaultLangcodeKey)->setValue($this->isDefaultTranslation(), FALSE);
+          $message = String::format('The default translation flag cannot be changed (@langcode).', array('@langcode' => $this->activeLangcode));
+          throw new \LogicException($message);
+        }
+        break;
     }
   }
 
@@ -684,6 +723,8 @@ public function addTranslation($langcode, array $values = array()) {
         $values[$name] = $field->getValue();
       }
     }
+    $values[$this->langcodeKey] = $langcode;
+    $values[$this->defaultLangcodeKey] = FALSE;
 
     $this->translations[$langcode]['status'] = static::TRANSLATION_CREATED;
     $translation = $this->getTranslation($langcode);
@@ -691,7 +732,7 @@ public function addTranslation($langcode, array $values = array()) {
 
     foreach ($values as $name => $value) {
       if (isset($definitions[$name]) && $definitions[$name]->isTranslatable()) {
-        $translation->$name = $value;
+        $translation->values[$name][$langcode] = $value;
       }
     }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 019e0a5..f0fcac8 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -401,14 +401,35 @@ public function getBaseFieldDefinitions($entity_type_id) {
   protected function buildBaseFieldDefinitions($entity_type_id) {
     $entity_type = $this->getDefinition($entity_type_id);
     $class = $entity_type->getClass();
+    $keys = array_filter($entity_type->getKeys());
 
     // Fail with an exception for non-fieldable entity types.
     if (!$entity_type->isSubclassOf('\Drupal\Core\Entity\FieldableEntityInterface')) {
       throw new \LogicException(String::format('Getting the base fields is not supported for entity type @type.', array('@type' => $entity_type->getLabel())));
     }
 
-    // Retrieve base field definitions and assign them the entity type provider.
+    // Retrieve base field definitions.
+    /** @var FieldStorageDefinitionInterface[] $base_field_definitions */
     $base_field_definitions = $class::baseFieldDefinitions($entity_type);
+
+    // Make sure translatable entity types are correctly defined.
+    if ($entity_type->isTranslatable()) {
+      // The langcode field should always be translatable if the entity type is.
+      if (isset($keys['langcode']) && isset($base_field_definitions[$keys['langcode']])) {
+        $base_field_definitions[$keys['langcode']]->setTranslatable(TRUE);
+      }
+      // A default_langcode field should always be defined.
+      if (!isset($base_field_definitions[$keys['default_langcode']])) {
+        $base_field_definitions[$keys['default_langcode']] = BaseFieldDefinition::create('boolean')
+          ->setLabel($this->t('Default translation'))
+          ->setDescription($this->t('A flag indicating whether this is the default translation.'))
+          ->setTranslatable(TRUE)
+          ->setRevisionable(TRUE)
+          ->setDefaultValue(TRUE);
+      }
+    }
+
+    // Assign base field definitions the entity type provider.
     $provider = $entity_type->getProvider();
     foreach ($base_field_definitions as $definition) {
       // @todo Remove this check once FieldDefinitionInterface exposes a proper
@@ -450,15 +471,21 @@ protected function buildBaseFieldDefinitions($entity_type_id) {
 
     // Ensure defined entity keys are there and have proper revisionable and
     // translatable values.
-    $keys = array_filter($entity_type->getKeys());
+    $fixed_keys = array('id', 'revision', 'uuid', 'bundle');
     foreach ($keys as $key => $field_name) {
-      if (isset($base_field_definitions[$field_name]) && in_array($key, array('id', 'revision', 'uuid', 'bundle')) && $base_field_definitions[$field_name]->isRevisionable()) {
+      if (isset($base_field_definitions[$field_name]) && in_array($key, $fixed_keys) && $base_field_definitions[$field_name]->isRevisionable()) {
         throw new \LogicException(String::format('The @field field cannot be revisionable as it is used as @key entity key.', array('@field' => $base_field_definitions[$field_name]->getLabel(), '@key' => $key)));
       }
-      if (isset($base_field_definitions[$field_name]) && in_array($key, array('id', 'revision', 'uuid', 'bundle', 'langcode')) && $base_field_definitions[$field_name]->isTranslatable()) {
+      if (isset($base_field_definitions[$field_name]) && in_array($key, $fixed_keys) && $base_field_definitions[$field_name]->isTranslatable()) {
         throw new \LogicException(String::format('The @field field cannot be translatable as it is used as @key entity key.', array('@field' => $base_field_definitions[$field_name]->getLabel(), '@key' => $key)));
       }
     }
+
+    // Make sure translatable entity types define the "langcode" field properly.
+    if ($entity_type->isTranslatable() && (!isset($keys['langcode']) || !isset($base_field_definitions[$keys['langcode']]) || !$base_field_definitions[$keys['langcode']]->isTranslatable())) {
+      throw new \LogicException(String::format('The @entity_type entity type cannot be translatable as it does not define a translatable "langcode" field.', array('@entity_type' => $entity_type->getLabel())));
+    }
+
     return $base_field_definitions;
   }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php
index b23cd9d..54a10d8 100644
--- a/core/lib/Drupal/Core/Entity/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/EntityType.php
@@ -238,6 +238,7 @@ public function __construct($definition) {
       'revision' => '',
       'bundle' => '',
       'langcode' => '',
+      'default_langcode' => 'default_langcode',
     );
     $this->handlers += array(
       'access' => 'Drupal\Core\Entity\EntityAccessControlHandler',
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php
index 5330ad5..5b6af02 100644
--- a/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityInterface.php
@@ -192,6 +192,8 @@ public function getFields($include_computed = TRUE);
    *
    * @param string $field_name
    *   The name of the field which is changed.
+   *
+   * @throws \LogicException
    */
   public function onChange($field_name);
 
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index 0c09ec9..6e1ecf1 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -182,8 +182,8 @@ public function addField($field, $type, $langcode) {
 
         $table = $this->ensureEntityTable($index_prefix, $sql_column, $type, $langcode, $base_table, $entity_id_field, $entity_tables);
 
-        // If there is a field storage (some specifiers are not, like
-        // default_langcode), check for case sensitivity.
+        // If there is a field storage (some specifiers are not), check for case
+        // sensitivity.
         if ($field_storage) {
           $column = $field_storage->getMainPropertyName();
           $base_field_property_definitions = $field_storage->getPropertyDefinitions();
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
index 8a5a4a7..5968446 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -67,6 +67,13 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
   protected $langcodeKey = FALSE;
 
   /**
+   * The default language entity key.
+   *
+   * @var string
+   */
+  protected $defaultLangcodeKey = FALSE;
+
+  /**
    * The base table of the entity.
    *
    * @var string
@@ -200,7 +207,7 @@ protected function initTableLayout() {
     if ($translatable) {
       $this->dataTable = $this->entityType->getDataTable() ?: $this->entityTypeId . '_field_data';
       $this->langcodeKey = $this->entityType->getKey('langcode');
-      $this->defaultLangcodeKey = $this->entityType->getKey('default_langcode') ?: 'default_langcode';
+      $this->defaultLangcodeKey = $this->entityType->getKey('default_langcode');
     }
     if ($revisionable && $translatable) {
       $this->revisionDataTable = $this->entityType->getRevisionDataTable() ?: $this->entityTypeId . '_field_revision';
@@ -342,11 +349,7 @@ public function getTableMapping(array $storage_definitions = NULL) {
         // the data table.
         $table_mapping
           ->setFieldNames($this->baseTable, $key_fields)
-          ->setFieldNames($this->dataTable, array_values(array_diff($all_fields, array($this->uuidKey))))
-          // Add the denormalized 'default_langcode' field to the mapping. Its
-          // value is identical to the query expression
-          // "base_table.langcode = data_table.langcode"
-          ->setExtraColumns($this->dataTable, array('default_langcode'));
+          ->setFieldNames($this->dataTable, array_values(array_diff($all_fields, array($this->uuidKey))));
       }
       elseif ($revisionable && $translatable) {
         // The revisionable multilingual layout stores key field values in the
@@ -356,31 +359,20 @@ public function getTableMapping(array $storage_definitions = NULL) {
         // holds the data field values for all non-revisionable fields. The data
         // field values of revisionable fields are denormalized in the data
         // table, as well.
-        $table_mapping->setFieldNames($this->baseTable, array_values(array_diff($key_fields, array($this->langcodeKey))));
+        $table_mapping->setFieldNames($this->baseTable, array_values($key_fields));
 
         // Like in the multilingual, non-revisionable case the UUID is not
         // in the data table. Additionally, do not store revision metadata
         // fields in the data table.
         $data_fields = array_values(array_diff($all_fields, array($this->uuidKey), $revision_metadata_fields));
-        $table_mapping
-          ->setFieldNames($this->dataTable, $data_fields)
-          // Add the denormalized 'default_langcode' field to the mapping. Its
-          // value is identical to the query expression
-          // "base_langcode = data_table.langcode" where "base_langcode" is
-          // the language code of the default revision.
-          ->setExtraColumns($this->dataTable, array('default_langcode'));
+        $table_mapping->setFieldNames($this->dataTable, $data_fields);
 
         $revision_base_fields = array_merge(array($this->idKey, $this->revisionKey, $this->langcodeKey), $revision_metadata_fields);
         $table_mapping->setFieldNames($this->revisionTable, $revision_base_fields);
 
         $revision_data_key_fields = array($this->idKey, $this->revisionKey, $this->langcodeKey);
         $revision_data_fields = array_diff($revisionable_fields, $revision_metadata_fields, array($this->langcodeKey));
-        $table_mapping
-          ->setFieldNames($this->revisionDataTable, array_merge($revision_data_key_fields, $revision_data_fields))
-          // Add the denormalized 'default_langcode' field to the mapping. Its
-          // value is identical to the query expression
-          // "revision_table.langcode = data_table.langcode".
-          ->setExtraColumns($this->revisionDataTable, array('default_langcode'));
+        $table_mapping->setFieldNames($this->revisionDataTable, array_merge($revision_data_key_fields, $revision_data_fields));
       }
 
       // Add dedicated tables.
@@ -673,12 +665,14 @@ protected function attachPropertyData(array &$entities) {
 
       $table_mapping = $this->getTableMapping();
       if ($this->revisionDataTable) {
-        // Find revisioned fields that are not entity keys.
-        $fields = array_diff($table_mapping->getFieldNames($this->revisionDataTable), $table_mapping->getFieldNames($this->baseTable));
+        // Find revisioned fields that are not entity keys. Exclude the langcode
+        // key as the base table holds only the default language.
+        $base_fields = array_diff($table_mapping->getFieldNames($this->baseTable), array($this->langcodeKey));
+        $fields = array_diff($table_mapping->getFieldNames($this->revisionDataTable), $base_fields);
 
         // Find fields that are not revisioned or entity keys. Data fields have
         // the same value regardless of entity revision.
-        $data_fields = array_diff($table_mapping->getFieldNames($this->dataTable), $fields, $table_mapping->getFieldNames($this->baseTable));
+        $data_fields = array_diff($table_mapping->getFieldNames($this->dataTable), $fields, $base_fields);
         if ($data_fields) {
           $fields = array_merge($fields, $data_fields);
           $query->leftJoin($this->dataTable, 'data', "(revision.$this->idKey = data.$this->idKey)");
@@ -703,10 +697,9 @@ protected function attachPropertyData(array &$entities) {
 
         // Field values in default language are stored with
         // LanguageInterface::LANGCODE_DEFAULT as key.
-        $langcode = empty($values['default_langcode']) ? $values[$this->langcodeKey] : LanguageInterface::LANGCODE_DEFAULT;
+        $langcode = empty($values[$this->defaultLangcodeKey]) ? $values[$this->langcodeKey] : LanguageInterface::LANGCODE_DEFAULT;
         $translations[$id][$langcode] = TRUE;
 
-
         foreach ($fields as $field_name) {
           $columns = $table_mapping->getColumnNames($field_name);
           // Do not key single-column fields by property name.
@@ -776,13 +769,13 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value
       //   apply to the default language. See http://drupal.org/node/1866330.
       // Default to the original entity language if not explicitly specified
       // otherwise.
-      if (!array_key_exists('default_langcode', $values)) {
-        $values['default_langcode'] = 1;
+      if (!array_key_exists($this->defaultLangcodeKey, $values)) {
+        $values[$this->defaultLangcodeKey] = 1;
       }
       // If the 'default_langcode' flag is explicitly not set, we do not care
       // whether the queried values are in the original entity language or not.
-      elseif ($values['default_langcode'] === NULL) {
-        unset($values['default_langcode']);
+      elseif ($values[$this->defaultLangcodeKey] === NULL) {
+        unset($values[$this->defaultLangcodeKey]);
       }
     }
 
@@ -1156,8 +1149,6 @@ protected function mapToDataStorageRecord(EntityInterface $entity, $table_name =
       $table_name = $this->dataTable;
     }
     $record = $this->mapToStorageRecord($entity, $table_name);
-    $record->{$this->langcodeKey} = $entity->language()->getId();
-    $record->default_langcode = intval($record->{$this->langcodeKey} == $entity->getUntranslated()->language()->getId());
     return $record;
   }
 
@@ -1171,7 +1162,7 @@ protected function mapToDataStorageRecord(EntityInterface $entity, $table_name =
    *   The revision id.
    */
   protected function saveRevision(EntityInterface $entity) {
-    $record = $this->mapToStorageRecord($entity, $this->revisionTable);
+    $record = $this->mapToStorageRecord($entity->getUntranslated(), $this->revisionTable);
 
     $entity->preSaveRevision($this, $record);
 
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
index b987b90..132ea06 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\DatabaseExceptionWrapper;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityStorageException;
@@ -163,7 +164,6 @@ public function requiresFieldStorageSchemaChanges(FieldStorageDefinitionInterfac
       $storage_definition->hasCustomStorage() != $original->hasCustomStorage() ||
       $storage_definition->getSchema() != $original->getSchema() ||
       $storage_definition->isRevisionable() != $original->isRevisionable() ||
-      $storage_definition->isTranslatable() != $original->isTranslatable() ||
       $table_mapping->allowsSharedTableStorage($storage_definition) != $table_mapping->allowsSharedTableStorage($original) ||
       $table_mapping->requiresDedicatedTableStorage($storage_definition) != $table_mapping->requiresDedicatedTableStorage($original)
     ) {
@@ -386,8 +386,17 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $
     // Only configurable fields currently support purging, so prevent deletion
     // of ones we can't purge if they have existing data.
     // @todo Add purging to all fields: https://www.drupal.org/node/2282119.
-    if (!($storage_definition instanceof FieldStorageConfigInterface) && $this->storage->countFieldData($storage_definition, TRUE)) {
-      throw new FieldStorageDefinitionUpdateForbiddenException('Unable to delete a field with data that can\'t be purged.');
+    try {
+      if (!($storage_definition instanceof FieldStorageConfigInterface) && $this->storage->countFieldData($storage_definition, TRUE)) {
+        throw new FieldStorageDefinitionUpdateForbiddenException('Unable to delete a field with data that cannot be purged.');
+      }
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      // This may happen when changing field storage schema, since we are not
+      // able to use a table mapping matching the passed storage definition.
+      // @todo Revisit this once we are able to instantiate the table mapping
+      //   properly. See https://www.drupal.org/node/2274017.
+      return;
     }
 
     // Retrieve a table mapping which contains the deleted field still.
@@ -506,13 +515,6 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res
             $schema[$table_name] = array_merge_recursive($schema[$table_name], $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names));
           }
         }
-
-        // Add the schema for extra fields.
-        foreach ($table_mapping->getExtraColumns($table_name) as $column_name) {
-          if ($column_name == 'default_langcode') {
-            $this->addDefaultLangcodeSchema($schema[$table_name]);
-          }
-        }
       }
 
       // Process tables after having gathered field information.
@@ -727,25 +729,6 @@ protected function getFieldForeignKeys($field_name, array $field_schema, array $
   }
 
   /**
-   * Returns the schema for the 'default_langcode' metadata field.
-   *
-   * @param array $schema
-   *   The table schema to add the field schema to, passed by reference.
-   *
-   * @return array
-   *   A schema field array for the 'default_langcode' metadata field.
-   */
-  protected function addDefaultLangcodeSchema(&$schema) {
-    $schema['fields']['default_langcode'] =  array(
-      'description' => 'Boolean indicating whether field values are in the default entity language.',
-      'type' => 'int',
-      'size' => 'tiny',
-      'not null' => TRUE,
-      'default' => 1,
-    );
-  }
-
-  /**
    * Loads stored schema data for the given entity type definition.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index b3b832b..73b288d 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -13,7 +13,7 @@
 interface TranslatableInterface {
 
   /**
-   * Returns the default language.
+   * Returns the translation language.
    *
    * @return \Drupal\Core\Language\LanguageInterface
    *   The language object.
@@ -21,6 +21,14 @@
   public function language();
 
   /**
+   * Checks whether the translation is the default one.
+   *
+   * @return bool
+   *   TRUE if the translation is the default one, FALSE otherwise.
+   */
+  public function isDefaultTranslation();
+
+  /**
    * Returns the languages the data is translated to.
    *
    * @param bool $include_default
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 469c314..bab5cd8 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -167,6 +167,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
       ->setDescription(t('The custom block language code.'))
+      ->setTranslatable(TRUE)
       ->setRevisionable(TRUE)
       ->setDisplayOptions('view', array(
         'type' => 'hidden',
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index 8b24aba..909abc3 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -224,6 +224,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
       ->setDescription(t('The comment language code.'))
+      ->setTranslatable(TRUE)
       ->setDisplayOptions('view', array(
         'type' => 'hidden',
       ))
diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc
index 341af53..fbb3a78 100644
--- a/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -102,7 +102,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
         foreach ($fields as $field_name => $definition) {
           // Allow to configure only fields supporting multilingual storage.
           // We skip our own fields as they are always translatable.
-          if (!empty($storage_definitions[$field_name]) && $storage_definitions[$field_name]->isTranslatable() && $storage_definitions[$field_name]->getProvider() != 'content_translation') {
+          if (!empty($storage_definitions[$field_name]) && $storage_definitions[$field_name]->isTranslatable() && $storage_definitions[$field_name]->getProvider() != 'content_translation' && $field_name != $entity_type->getKey('langcode') && $field_name != $entity_type->getKey('default_langcode')) {
             $form['settings'][$entity_type_id][$bundle]['fields'][$field_name] = array(
               '#label' => $definition->getLabel(),
               '#type' => 'checkbox',
diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
index 78d7483..5570a2a 100644
--- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -360,6 +360,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
       ->setDescription(t('The menu link language code.'))
+      ->setTranslatable(TRUE)
       ->setDisplayOptions('view', array(
         'type' => 'hidden',
       ))
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index 13ad744..6e33d27 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -353,6 +353,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
       ->setDescription(t('The node language code.'))
+      ->setTranslatable(TRUE)
       ->setRevisionable(TRUE)
       ->setDisplayOptions('view', array(
         'type' => 'hidden',
diff --git a/core/modules/serialization/src/Tests/EntitySerializationTest.php b/core/modules/serialization/src/Tests/EntitySerializationTest.php
index a05bce6..04841a9 100644
--- a/core/modules/serialization/src/Tests/EntitySerializationTest.php
+++ b/core/modules/serialization/src/Tests/EntitySerializationTest.php
@@ -95,21 +95,24 @@ public function testNormalize() {
       'type' => array(
         array('value' => 'entity_test_mulrev'),
       ),
+      'created' => array(
+        array('value' => $this->entity->created->value),
+      ),
       'user_id' => array(
         array('target_id' => $this->values['user_id']),
       ),
       'revision_id' => array(
         array('value' => 1),
       ),
+      'default_langcode' => array(
+        array('value' => TRUE),
+      ),
       'field_test_text' => array(
         array(
           'value' => $this->values['field_test_text']['value'],
           'format' => $this->values['field_test_text']['format'],
         ),
       ),
-      'created' => array(
-        array('value' => $this->entity->created->value),
-      ),
     );
 
     $normalized = $this->serializer->normalize($this->entity);
@@ -175,10 +178,11 @@ public function testSerialize() {
       'langcode' => '<langcode><value>en</value></langcode>',
       'name' => '<name><value>' . $this->values['name'] . '</value></name>',
       'type' => '<type><value>entity_test_mulrev</value></type>',
+      'created' => '<created><value>' . $this->entity->created->value . '</value></created>',
       'user_id' => '<user_id><target_id>' . $this->values['user_id'] . '</target_id></user_id>',
       'revision_id' => '<revision_id><value>' . $this->entity->getRevisionId() . '</value></revision_id>',
+      'default_langcode' => '<default_langcode><value>1</value></default_langcode>',
       'field_test_text' => '<field_test_text><value>' . $this->values['field_test_text']['value'] . '</value><format>' . $this->values['field_test_text']['format'] . '</format></field_test_text>',
-      'created' => '<created><value>' . $this->entity->created->value . '</value></created>',
     );
     // Sort it in the same order as normalised.
     $expected = array_merge($normalized, $expected);
diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php
index 9fd0332..a2179f9 100644
--- a/core/modules/shortcut/src/Entity/Shortcut.php
+++ b/core/modules/shortcut/src/Entity/Shortcut.php
@@ -163,6 +163,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
       ->setDescription(t('The language code of the shortcut.'))
+      ->setTranslatable(TRUE)
       ->setDisplayOptions('view', array(
         'type' => 'hidden',
       ))
diff --git a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php
index 65bb740..aab0d28 100644
--- a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Tests\Entity;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\entity_test\Entity\EntityTestMulRev;
 use Drupal\language\Entity\ConfigurableLanguage;
@@ -147,6 +148,7 @@ public function testMultilingualProperties() {
    */
   protected function doTestMultilingualProperties($entity_type) {
     $langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('langcode');
+    $default_langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('default_langcode');
     $name = $this->randomMachineName();
     $uid = mt_rand(0, 127);
     $langcode = $this->langcodes[0];
@@ -249,16 +251,16 @@ protected function doTestMultilingualProperties($entity_type) {
     $this->assertEqual(count($entities), 2, format_string('%entity_type: Two entities correctly loaded by name.', array('%entity_type' => $entity_type)));
     // @todo The default language condition should go away in favor of an
     // explicit parameter.
-    $entities = entity_load_multiple_by_properties($entity_type, array('name' => $properties[$langcode]['name'][0], 'default_langcode' => 0));
+    $entities = entity_load_multiple_by_properties($entity_type, array('name' => $properties[$langcode]['name'][0], $default_langcode_key => 0));
     $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity correctly loaded by name translation.', array('%entity_type' => $entity_type)));
     $entities = entity_load_multiple_by_properties($entity_type, array($langcode_key => $default_langcode, 'name' => $name));
     $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity correctly loaded by name and language.', array('%entity_type' => $entity_type)));
 
     $entities = entity_load_multiple_by_properties($entity_type, array($langcode_key => $langcode, 'name' => $properties[$langcode]['name'][0]));
     $this->assertEqual(count($entities), 0, format_string('%entity_type: No entity loaded by name translation specifying the translation language.', array('%entity_type' => $entity_type)));
-    $entities = entity_load_multiple_by_properties($entity_type, array($langcode_key => $langcode, 'name' => $properties[$langcode]['name'][0], 'default_langcode' => 0));
+    $entities = entity_load_multiple_by_properties($entity_type, array($langcode_key => $langcode, 'name' => $properties[$langcode]['name'][0], $default_langcode_key => 0));
     $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity loaded by name translation and language specifying to look for translations.', array('%entity_type' => $entity_type)));
-    $entities = entity_load_multiple_by_properties($entity_type, array('user_id' => $properties[$langcode]['user_id'][0], 'default_langcode' => NULL));
+    $entities = entity_load_multiple_by_properties($entity_type, array('user_id' => $properties[$langcode]['user_id'][0], $default_langcode_key => NULL));
     $this->assertEqual(count($entities), 2, format_string('%entity_type: Two entities loaded by uid without caring about property translatability.', array('%entity_type' => $entity_type)));
 
     // Test property conditions and orders with multiple languages in the same
@@ -313,6 +315,9 @@ protected function doTestEntityTranslationAPI($entity_type) {
     $default_langcode = $this->langcodes[0];
     $langcode = $this->langcodes[1];
     $langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('langcode');
+    $default_langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('default_langcode');
+
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     $entity = $this->entityManager
       ->getStorage($entity_type)
       ->create(array('name' => $this->randomMachineName(), $langcode_key => LanguageInterface::LANGCODE_NOT_SPECIFIED));
@@ -324,12 +329,13 @@ protected function doTestEntityTranslationAPI($entity_type) {
     // Verify that we obtain the entity object itself when we attempt to
     // retrieve a translation referring to it.
     $translation = $entity->getTranslation($langcode);
-    $this->assertEqual($entity, $translation, 'The translation object corresponding to a non-default language is the entity object itself when the entity is language-neutral.');
+    $this->assertIdentical($entity, $translation, 'The translation object corresponding to a non-default language is the entity object itself when the entity is language-neutral.');
     $entity->{$langcode_key}->value = $default_langcode;
     $translation = $entity->getTranslation($default_langcode);
-    $this->assertEqual($entity, $translation, 'The translation object corresponding to the default language (explicit) is the entity object itself.');
+    $this->assertIdentical($entity, $translation, 'The translation object corresponding to the default language (explicit) is the entity object itself.');
     $translation = $entity->getTranslation(LanguageInterface::LANGCODE_DEFAULT);
-    $this->assertEqual($entity, $translation, 'The translation object corresponding to the default language (implicit) is the entity object itself.');
+    $this->assertIdentical($entity, $translation, 'The translation object corresponding to the default language (implicit) is the entity object itself.');
+    $this->assertTrue($entity->{$default_langcode_key}->value, 'The translation object is the default one.');
 
     // Create a translation and verify that the translation object and the
     // original object behave independently.
@@ -340,18 +346,57 @@ protected function doTestEntityTranslationAPI($entity_type) {
     $this->assertNotIdentical($entity, $translation, 'The entity and the translation object differ from one another.');
     $this->assertTrue($entity->hasTranslation($langcode), 'The new translation exists.');
     $this->assertEqual($translation->language()->getId(), $langcode, 'The translation language matches the specified one.');
+    $this->assertEqual($translation->{$langcode_key}->value, $langcode, 'The translation field language value matches the specified one.');
+    $this->assertFalse($translation->{$default_langcode_key}->value, 'The translation object is not the default one.');
     $this->assertEqual($translation->getUntranslated()->language()->getId(), $default_langcode, 'The original language can still be retrieved.');
     $translation->name->value = $name_translated;
     $this->assertEqual($entity->name->value, $name, 'The original name is retained after setting a translated value.');
     $entity->name->value = $name;
     $this->assertEqual($translation->name->value, $name_translated, 'The translated name is retained after setting the original value.');
 
-    // Save the translation and check that the expecte hooks are fired.
+    // Save the translation and check that the expected hooks are fired.
     $translation->save();
     $hooks = $this->getHooksInfo();
     $this->assertEqual($hooks['entity_translation_insert'], $langcode, 'The generic entity translation insertion hook has fired.');
     $this->assertEqual($hooks[$entity_type . '_translation_insert'], $langcode, 'The entity-type-specific entity translation insertion hook has fired.');
 
+    // Verify that changing translation language causes an exception to be
+    // thrown.
+    $message = 'The translation language cannot be changed.';
+    try {
+      $translation->{$langcode_key}->value = $this->langcodes[2];
+      $this->fail($message);
+    }
+    catch (\LogicException $e) {
+      $this->pass($message);
+    }
+
+    // Verify that reassigning the same translation language is allowed.
+    $message = 'The translation language can be reassigned the same value.';
+    try {
+      $translation->{$langcode_key}->value = $langcode;
+      $this->pass($message);
+    }
+    catch (\LogicException $e) {
+      $this->fail($message);
+    }
+
+    // Verify that changing the default translation flag causes an exception to
+    // be thrown.
+    $message = 'The default translation flag cannot be changed.';
+    foreach ($entity->getTranslationLanguages() as $t_langcode => $language) {
+      $translation = $entity->getTranslation($t_langcode);
+      $default = $translation->isDefaultTranslation();
+      try {
+        $translation->{$default_langcode_key}->value = !$default;
+        $this->fail($message);
+      }
+      catch (\LogicException $e) {
+        $this->pass($message);
+      }
+      $this->assertEqual($translation->{$default_langcode_key}->value, $default);
+    }
+
     // Check that after loading an entity the language is the default one.
     $entity = $this->reloadEntity($entity);
     $this->assertEqual($entity->language()->getId(), $default_langcode, 'The loaded entity is the original one.');
@@ -588,9 +633,16 @@ function testFieldDefinitions() {
     $this->assertTrue(!isset($base_field_definitions['id']->translatable), 'Translatability for the <em>id</em> field is not defined.');
     $this->assertFalse($definitions['id']->isTranslatable(), 'Field translatability is disabled by default.');
 
-    // Check that entity ids and langcode fields cannot be translatable.
-    foreach (array('id', 'uuid', 'revision_id', 'type', 'langcode') as $name) {
-      $this->state->set('entity_test.field_definitions.translatable', array($name => TRUE));
+    // Check that entity id keys have the expect translatability.
+    $translatable_fields = array(
+      'id' => TRUE,
+      'uuid' => TRUE,
+      'revision_id' => TRUE,
+      'type' => TRUE,
+      'langcode' => FALSE,
+    );
+    foreach ($translatable_fields as $name => $translatable) {
+      $this->state->set('entity_test.field_definitions.translatable', array($name => $translatable));
       $this->entityManager->clearCachedFieldDefinitions();
       $message = format_string('Field %field cannot be translatable.', array('%field' => $name));
 
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
index 0549257..bec87c4 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
@@ -77,7 +77,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
 
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language code'))
-      ->setDescription(t('The language code of the test entity.'));
+      ->setDescription(t('The language code of the test entity.'))
+      ->setTranslatable(TRUE);
 
     $fields['name'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Name'))
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php
index 0b5585b..c50f2c7 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php
@@ -34,6 +34,7 @@
  *     "bundle" = "type",
  *     "label" = "name",
  *     "langcode" = "custom_langcode_key",
+ *     "default_langcode" = "custom_default_langcode_key",
  *   },
  *   links = {
  *     "canonical" = "/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}",
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index 043c90d..7a1cc5f 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -121,6 +121,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language'))
       ->setDescription(t('The term language code.'))
+      ->setTranslatable(TRUE)
       ->setDisplayOptions('view', array(
         'type' => 'hidden',
       ))
diff --git a/core/modules/user/src/AccountForm.php b/core/modules/user/src/AccountForm.php
index 73055ef..738514c 100644
--- a/core/modules/user/src/AccountForm.php
+++ b/core/modules/user/src/AccountForm.php
@@ -345,7 +345,7 @@ public function alterPreferredLangcodeDescription(array $element) {
    *   The current state of the form.
    */
   public function syncUserLangcode($entity_type_id, UserInterface $user, array &$form, FormStateInterface &$form_state) {
-    $user->langcode = $user->preferred_langcode;
+    $user->getUntranslated()->langcode = $user->preferred_langcode;
   }
 
   /**
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index 76122bc..f770ee3 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -475,7 +475,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
 
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language code'))
-      ->setDescription(t('The user language code.'));
+      ->setDescription(t('The user language code.'))
+      ->setTranslatable(TRUE);
 
     $fields['preferred_langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Preferred language code'))
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
index 8c159ec..411e670 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
@@ -37,6 +37,20 @@ class EntityManagerTest extends UnitTestCase {
   protected $entityManager;
 
   /**
+   * The entity type definition.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityType;
+
+  /**
+   * An instance of the test entity.
+   *
+   * @var \Drupal\Tests\Core\Entity\EntityManagerTestEntity|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entity;
+
+  /**
    * The plugin discovery.
    *
    * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -146,17 +160,48 @@ protected function setUp() {
     $this->formBuilder = $this->getMock('Drupal\Core\Form\FormBuilderInterface');
     $this->controllerResolver = $this->getClassResolverStub();
 
-    $this->container = $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator);
-
     $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
 
     $this->typedDataManager = $this->getMockBuilder('\Drupal\Core\TypedData\TypedDataManager')
       ->disableOriginalConstructor()
       ->getMock();
 
+    $map = [
+      ['field_item:boolean', TRUE, ['class' => 'Drupal\Core\Field\Plugin\Field\FieldType\BooleanItem']],
+    ];
+
+    $this->typedDataManager->expects($this->any())
+      ->method('getDefinition')
+      ->willReturnMap($map);
+
     $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
     $this->installedDefinitions = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface');
+
+    $this->container = $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator);
+    $this->container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
+    \Drupal::setContainer($this->container);
+
+    $field_type_manager = $this->getMock('Drupal\Core\Field\FieldTypePluginManagerInterface');
+    $field_type_manager->expects($this->any())
+      ->method('getDefaultStorageSettings')
+      ->willReturn(array());
+    $field_type_manager->expects($this->any())
+      ->method('getDefaultFieldSettings')
+      ->willReturn(array());
+
+    $string_translation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
+
+    $map = [
+      ['cache_tags.invalidator', 1, $this->cacheTagsInvalidator],
+      ['plugin.manager.field.field_type', 1, $field_type_manager],
+      ['string_translation', 1, $string_translation],
+      ['typed_data_manager', 1, $this->typedDataManager],
+    ];
+
+    $this->container->expects($this->any())
+      ->method('get')
+      ->willReturnMap($map);
   }
 
   /**
@@ -522,6 +567,100 @@ public function testGetFieldStorageDefinitions() {
   }
 
   /**
+   * Tests the getBaseFieldDefinitions() method with a translatable entity type.
+   *
+   * @covers ::getBaseFieldDefinitions
+   * @covers ::buildBaseFieldDefinitions
+   *
+   * @dataProvider providerTestGetBaseFieldDefinitionsTranslatableEntityTypeDefaultLangcode
+   */
+  public function testGetBaseFieldDefinitionsTranslatableEntityTypeDefaultLangcode($default_langcode_key) {
+    $this->setUpEntityWithFieldDefinition(FALSE, 'id', array('langcode' => 'langcode', 'default_langcode' => $default_langcode_key));
+
+    $field_definition = $this->getMockBuilder('Drupal\Core\Field\BaseFieldDefinition')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $field_definition->expects($this->atLeastOnce())
+      ->method('isTranslatable')
+      ->willReturn(TRUE);
+
+    $entity_class = get_class($this->entity);
+    $entity_class::$baseFieldDefinitions += array('langcode' => $field_definition);
+
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('isTranslatable')
+      ->willReturn(TRUE);
+
+    $definitions = $this->entityManager->getBaseFieldDefinitions('test_entity_type');
+
+    $this->assertTrue(isset($definitions[$default_langcode_key]));
+  }
+
+  /**
+   * Provides test data for testGetBaseFieldDefinitionsTranslatableEntityTypeDefaultLangcode().
+   *
+   * @return array
+   *   Test data.
+   */
+  public function providerTestGetBaseFieldDefinitionsTranslatableEntityTypeDefaultLangcode() {
+    return [
+      ['default_langcode'],
+      ['custom_default_langcode_key'],
+    ];
+  }
+
+  /**
+   * Tests the getBaseFieldDefinitions() method with a translatable entity type.
+   *
+   * @covers ::getBaseFieldDefinitions
+   * @covers ::buildBaseFieldDefinitions
+   *
+   * @expectedException \LogicException
+   * @expectedExceptionMessage The Test entity type cannot be translatable as it does not define a translatable "langcode" field.
+   *
+   * @dataProvider providerTestGetBaseFieldDefinitionsTranslatableEntityTypeLangcode
+   */
+  public function testGetBaseFieldDefinitionsTranslatableEntityTypeLangcode($provide_key, $provide_field, $translatable) {
+    $keys = $provide_key ? array('langcode' => 'langcode') : array();
+    $this->setUpEntityWithFieldDefinition(FALSE, 'id', $keys);
+
+    if ($provide_field) {
+      $field_definition = $this->getMockBuilder('Drupal\Core\Field\BaseFieldDefinition')
+        ->disableOriginalConstructor()
+        ->getMock();
+      $field_definition->expects($this->any())
+        ->method('isTranslatable')
+        ->willReturn($translatable);
+
+      $entity_class = get_class($this->entity);
+      $entity_class::$baseFieldDefinitions += array('langcode' => $field_definition);
+    }
+
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('isTranslatable')
+      ->willReturn(TRUE);
+    $this->entityType->expects($this->atLeastOnce())
+      ->method('getLabel')
+      ->willReturn('Test');
+
+    $this->entityManager->getBaseFieldDefinitions('test_entity_type');
+  }
+
+  /**
+   * Provides test data for testGetBaseFieldDefinitionsTranslatableEntityTypeLangcode().
+   *
+   * @return array
+   *   Test data.
+   */
+  public function providerTestGetBaseFieldDefinitionsTranslatableEntityTypeLangcode() {
+    return [
+      [FALSE, TRUE, TRUE],
+      [TRUE, FALSE, TRUE],
+      [TRUE, TRUE, FALSE],
+    ];
+  }
+
+  /**
    * Tests the getBaseFieldDefinitions() method with caching.
    *
    * @covers ::getBaseFieldDefinitions
@@ -668,6 +807,10 @@ public function testGetBaseFieldDefinitionsInvalidDefinition() {
     $langcode_definition = $this->setUpEntityWithFieldDefinition(FALSE, 'langcode', array('langcode' => 'langcode'));
     $langcode_definition->expects($this->once())
       ->method('isTranslatable')
+      ->will($this->returnValue(FALSE));
+
+    $this->entityType->expects($this->any())
+      ->method('isTranslatable')
       ->will($this->returnValue(TRUE));
 
     $this->entityManager->getBaseFieldDefinitions('test_entity_type');
@@ -725,19 +868,20 @@ public function testGetFieldDefinitionsProvider() {
    *   A field definition object.
    */
   protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $field_definition_id = 'id', $entity_keys = array()) {
-    $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
-    $entity = $this->getMockBuilder('Drupal\Tests\Core\Entity\EntityManagerTestEntity')
+    $this->entityType = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
+
+    $this->entity = $this->getMockBuilder('Drupal\Tests\Core\Entity\EntityManagerTestEntity')
       ->disableOriginalConstructor()
       ->getMockForAbstractClass();
-    $entity_class = get_class($entity);
+    $entity_class = get_class($this->entity);
 
-    $entity_type->expects($this->any())
+    $this->entityType->expects($this->any())
       ->method('getClass')
       ->will($this->returnValue($entity_class));
-    $entity_type->expects($this->any())
+    $this->entityType->expects($this->any())
       ->method('getKeys')
-      ->will($this->returnValue($entity_keys));
-    $entity_type->expects($this->any())
+      ->will($this->returnValue($entity_keys + array('default_langcode' => 'default_langcode')));
+    $this->entityType->expects($this->any())
       ->method('isSubclassOf')
       ->with($this->equalTo('\Drupal\Core\Entity\FieldableEntityInterface'))
       ->will($this->returnValue(TRUE));
@@ -762,14 +906,14 @@ protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $f
     $override_entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
     $override_entity_type->expects($this->any())
        ->method('getClass')
-       ->will($this->returnValue(get_class($entity)));
+       ->will($this->returnValue(get_class($this->entity)));
 
     $override_entity_type->expects($this->any())
       ->method('getHandlerClass')
       ->with('storage')
       ->will($this->returnValue('\Drupal\Tests\Core\Entity\TestConfigEntityStorage'));
 
-    $this->setUpEntityManager(array('test_entity_type' => $entity_type, 'base_field_override' => $override_entity_type));
+    $this->setUpEntityManager(array('test_entity_type' => $this->entityType, 'base_field_override' => $override_entity_type));
 
     return $field_definition;
   }
@@ -1059,7 +1203,7 @@ public function testGetFieldMap() {
       ->will($this->returnValue($entity_class));
     $entity_type->expects($this->any())
       ->method('getKeys')
-      ->will($this->returnValue(array()));
+      ->will($this->returnValue(array('default_langcode' => 'default_langcode')));
     $entity_type->expects($this->any())
       ->method('id')
       ->will($this->returnValue('test_entity_type'));
@@ -1202,7 +1346,7 @@ public function testGetFieldMapByFieldType() {
       ->will($this->returnValue($entity_class));
     $entity_type->expects($this->any())
       ->method('getKeys')
-      ->will($this->returnValue(array()));
+      ->will($this->returnValue(array('default_langcode' => 'default_langcode')));
     $entity_type->expects($this->any())
       ->method('id')
       ->will($this->returnValue('test_entity_type'));
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php
index c4ae0b6..6a61fa1 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php
@@ -38,7 +38,7 @@ protected function setUpEntityType($definition) {
    */
   public function testGetKeys($entity_keys, $expected) {
     $entity_type = $this->setUpEntityType(array('entity_keys' => $entity_keys));
-    $this->assertSame($expected, $entity_type->getKeys());
+    $this->assertSame($expected + ['default_langcode' => 'default_langcode'], $entity_type->getKeys());
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
index 9a786d5..237435f 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
@@ -89,7 +89,6 @@ protected function setUp() {
    * @covers ::getFieldUniqueKeys
    * @covers ::getFieldForeignKeys
    * @covers ::getFieldSchemaData
-   * @covers ::addDefaultLangcodeSchema
    * @covers ::processBaseTable
    * @covers ::processIdentifierSchema
    */
@@ -321,13 +320,6 @@ public function testGetSchemaBase() {
             'type' => 'int',
             'not null' => FALSE,
           ),
-          'default_langcode' => array(
-            'description' => 'Boolean indicating whether field values are in the default entity language.',
-            'type' => 'int',
-            'size' => 'tiny',
-            'not null' => TRUE,
-            'default' => 1,
-          ),
         ),
         'primary key' => array('id'),
         'unique keys' => array(
diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php
index ec24b1a..8d5b681 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php
@@ -643,7 +643,6 @@ public function testGetTableMappingTranslatable(array $entity_keys) {
     $expected = array();
     $actual = $mapping->getExtraColumns('entity_test');
     $this->assertEquals($expected, $actual);
-    $expected = array('default_langcode');
     $actual = $mapping->getExtraColumns('entity_test_field_data');
     $this->assertEquals($expected, $actual);
   }
@@ -704,7 +703,6 @@ public function testGetTableMappingTranslatableWithFields(array $entity_keys) {
     $expected = array();
     $actual = $mapping->getExtraColumns('entity_test');
     $this->assertEquals($expected, $actual);
-    $expected = array('default_langcode');
     $actual = $mapping->getExtraColumns('entity_test_field_data');
     $this->assertEquals($expected, $actual);
   }
@@ -761,13 +759,13 @@ public function testGetTableMappingRevisionableTranslatable(array $entity_keys)
     );
     $this->assertEquals($expected, $mapping->getTableNames());
 
-    // The language code is not stored on the base table, but on the revision
-    // table.
+    // The default language code is stored on the base table.
     $expected = array_values(array_filter(array(
       $entity_keys['id'],
       $entity_keys['revision'],
       $entity_keys['bundle'],
       $entity_keys['uuid'],
+      $entity_keys['langcode'],
     )));
     $actual = $mapping->getFieldNames('entity_test');
     $this->assertEquals($expected, $actual);
@@ -803,7 +801,6 @@ public function testGetTableMappingRevisionableTranslatable(array $entity_keys)
     $this->assertEquals($expected, $actual);
     $actual = $mapping->getExtraColumns('entity_test_revision');
     $this->assertEquals($expected, $actual);
-    $expected = array('default_langcode');
     $actual = $mapping->getExtraColumns('entity_test_field_data');
     $this->assertEquals($expected, $actual);
     $actual = $mapping->getExtraColumns('entity_test_field_revision');
@@ -891,13 +888,13 @@ public function testGetTableMappingRevisionableTranslatableWithFields(array $ent
       );
       $this->assertEquals($expected, $mapping->getTableNames());
 
-      // The language code is not stored on the base table, but on the revision
-      // table.
+      // The default language code is not stored on the base table.
       $expected = array_values(array_filter(array(
         $entity_keys['id'],
         $entity_keys['revision'],
         $entity_keys['bundle'],
         $entity_keys['uuid'],
+        $entity_keys['langcode'],
       )));
       $actual = $mapping->getFieldNames('entity_test');
       $this->assertEquals($expected, $actual);
@@ -933,7 +930,6 @@ public function testGetTableMappingRevisionableTranslatableWithFields(array $ent
       $this->assertEquals($expected, $actual);
       $actual = $mapping->getExtraColumns('entity_test_revision');
       $this->assertEquals($expected, $actual);
-      $expected = array('default_langcode');
       $actual = $mapping->getExtraColumns('entity_test_field_data');
       $this->assertEquals($expected, $actual);
       $actual = $mapping->getExtraColumns('entity_test_field_revision');
