diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 4f11f1e..0b89c26 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -822,37 +822,17 @@ public function addTranslation($langcode, array $values = array()) {
       throw new \InvalidArgumentException("The entity cannot be translated since it is language neutral ({$this->defaultLangcode}).");
     }
 
-    // Instantiate a new empty entity so default values will be populated in the
-    // specified language.
-    $entity_type = $this->getEntityType();
-
-    $default_values = array(
-      $entity_type->getKey('bundle') => $this->bundle(),
-      $this->langcodeKey => $langcode,
-    );
-    $entity = $this->entityManager()
-      ->getStorage($this->getEntityTypeId())
-      ->create($default_values);
-
-    foreach ($entity as $name => $field) {
-      if (!isset($values[$name]) && !$field->isEmpty()) {
-        $values[$name] = $field->getValue();
-      }
+    // Initialize the translation object if the storage supports that.
+    $storage = $this->entityManager()->getStorage($this->getEntityTypeId());
+    if ($storage instanceof ContentEntityStorageInterface) {
+      $values[$this->langcodeKey] = $langcode;
+      $values[$this->defaultLangcodeKey] = FALSE;
+      $this->translations[$langcode]['status'] = static::TRANSLATION_CREATED;
+      return $storage->createTranslation($this, $langcode, $values);
     }
-    $values[$this->langcodeKey] = $langcode;
-    $values[$this->defaultLangcodeKey] = FALSE;
-
-    $this->translations[$langcode]['status'] = static::TRANSLATION_CREATED;
-    $translation = $this->getTranslation($langcode);
-    $definitions = $translation->getFieldDefinitions();
-
-    foreach ($values as $name => $value) {
-      if (isset($definitions[$name]) && $definitions[$name]->isTranslatable()) {
-        $translation->values[$name][$langcode] = $value;
-      }
+    else {
+      throw new \LogicException('The storage handler cannot create entity translations.');
     }
-
-    return $translation;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index 2a5475e..4306a12 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -13,7 +13,10 @@
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
-abstract class ContentEntityStorageBase extends EntityStorageBase implements DynamicallyFieldableEntityStorageInterface {
+/**
+ * Base class for content entity storage handlers.
+ */
+abstract class ContentEntityStorageBase extends EntityStorageBase implements ContentEntityStorageInterface {
 
   /**
    * The entity bundle key.
@@ -87,13 +90,32 @@ protected function doCreate(array $values) {
       $bundle = $values[$this->bundleKey];
     }
     $entity = new $this->entityClass(array(), $this->entityTypeId, $bundle);
+    $this->initFieldValues($entity, $values);
+    return $entity;
+  }
 
+  /**
+   * Initializes field values.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   An entity object.
+   * @param array $values
+   *   (optional) An associative array of initial field values keyed by field
+   *   name. If none is provided default values will be applied.
+   * @param array $field_names
+   *   (optional) An associative array of field names to be initialized. If none
+   *   is provided all fields will be initialized.
+   */
+  protected function initFieldValues(ContentEntityInterface $entity, array $values = [], array $field_names = []) {
+    // Populate field values.
     foreach ($entity as $name => $field) {
-      if (isset($values[$name])) {
-        $entity->$name = $values[$name];
-      }
-      elseif (!array_key_exists($name, $values)) {
-        $entity->get($name)->applyDefaultValue();
+      if (!$field_names || isset($field_names[$name])) {
+        if (isset($values[$name])) {
+          $entity->$name = $values[$name];
+        }
+        elseif (!array_key_exists($name, $values)) {
+          $entity->get($name)->applyDefaultValue();
+        }
       }
       unset($values[$name]);
     }
@@ -102,7 +124,21 @@ protected function doCreate(array $values) {
     foreach ($values as $name => $value) {
       $entity->$name = $value;
     }
-    return $entity;
+
+    // Make sure modules can alter field initial values.
+    $this->invokeHook('field_values_init', $entity);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) {
+    $translation = $entity->getTranslation($langcode);
+    $definitions = array_filter($translation->getFieldDefinitions(), function(FieldDefinitionInterface $definition) { return $definition->isTranslatable(); });
+    $field_names = array_map(function(FieldDefinitionInterface $definition) { return $definition->getName(); }, $definitions);
+    $this->initFieldValues($translation, $values, $field_names);
+    $this->invokeHook('translation_create', $entity);
+    return $translation;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
new file mode 100644
index 0000000..f62e0ac
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\ContentEntityStorageInterface.
+ */
+
+namespace Drupal\Core\Entity;
+
+/**
+ * A storage that supports content entity types.
+ */
+interface ContentEntityStorageInterface extends DynamicallyFieldableEntityStorageInterface {
+
+  /**
+   * Constructs a new entity translation object, without permanently saving it.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity object being translated.
+   * @param string $langcode
+   *   The translation language code.
+   * @param array $values
+   *   (optional) An associative array of initial field values keyed by field
+   *   name. If none is provided default values will be applied.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface
+   *   A new entity translation object.
+   */
+  public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []);
+
+}
