diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 4f11f1e..5d22d45 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -822,37 +822,11 @@ 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();
-      }
-    }
-    $values[$this->langcodeKey] = $langcode;
-    $values[$this->defaultLangcodeKey] = FALSE;
-
+    // Initialize the translation object.
+    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+    $storage = $this->entityManager()->getStorage($this->getEntityTypeId());
     $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;
-      }
-    }
-
-    return $translation;
+    return $storage->createTranslation($this, $langcode, $values);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
index 2a5475e..844f388 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php
@@ -87,13 +87,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 +121,23 @@ 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);
+    $values[$this->langcodeKey] = $langcode;
+    $values[$this->getEntityType()->getKey('default_langcode')] = FALSE;
+    $this->initFieldValues($translation, $values, $field_names);
+    $this->invokeHook('translation_create', $entity);
+    return $translation;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/entity.api.php b/core/lib/Drupal/Core/Entity/entity.api.php
index 8883f78..85989bf 100644
--- a/core/lib/Drupal/Core/Entity/entity.api.php
+++ b/core/lib/Drupal/Core/Entity/entity.api.php
@@ -780,10 +780,9 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) {
 }
 
 /**
- * Act on a newly created entity.
+ * Acts when creating a new entity.
  *
- * This hook runs after a new entity object has just been instantiated. It can
- * be used to set initial values, e.g. to provide defaults.
+ * This hook runs after a new entity object has just been instantiated.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object.
@@ -792,16 +791,13 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) {
  * @see hook_ENTITY_TYPE_create()
  */
 function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
-  if ($entity instanceof FieldableEntityInterface && !$entity->foo->value) {
-    $entity->foo->value = 'some_initial_value';
-  }
+  \Drupal::logger('example')->info('Entity created: @label', ['@label' => $entity->label()]);
 }
 
 /**
- * Act on a newly created entity of a specific type.
+ * Acts when creating a new entity of a specific type.
  *
- * This hook runs after a new entity object has just been instantiated. It can
- * be used to set initial values, e.g. to provide defaults.
+ * This hook runs after a new entity object has just been instantiated.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity object.
@@ -810,9 +806,7 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
  * @see hook_entity_create()
  */
 function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
-  if (!$entity->foo->value) {
-    $entity->foo->value = 'some_initial_value';
-  }
+  \Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]);
 }
 
 /**
@@ -1012,6 +1006,38 @@ function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) {
 }
 
 /**
+ * Acts when creating a new entity translation.
+ *
+ * This hook runs after a new entity translation object has just been
+ * instantiated.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $translation
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_translation_create()
+ */
+function hook_entity_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
+  \Drupal::logger('example')->info('Entity translation created: @label', ['@label' => $translation->label()]);
+}
+
+/**
+ * Acts when creating a new entity translation of a specific type.
+ *
+ * This hook runs after a new entity translation object has just been
+ * instantiated.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $translation
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_translation_create()
+ */
+function hook_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
+  \Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]);
+}
+
+/**
  * Respond to creation of a new entity translation.
  *
  * This hook runs once the entity translation has been stored. Note that hook
@@ -1887,6 +1913,44 @@ function hook_entity_field_access_alter(array &$grants, array $context) {
 }
 
 /**
+ * Acts when initializing a fieldable entity object.
+ *
+ * This hook runs after a new entity object or a new entity translation object
+ * has just been instantiated. It can be used to set initial values, e.g. to
+ * provide defaults.
+ *
+ * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_ENTITY_TYPE_field_values_init()
+ */
+function hook_entity_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
+  if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface && !$entity->foo->value) {
+    $entity->foo->value = 'some_initial_value';
+  }
+}
+
+/**
+ * Acts when initializing a fieldable entity object.
+ *
+ * This hook runs after a new entity object or a new entity translation object
+ * has just been instantiated. It can be used to set initial values, e.g. to
+ * provide defaults.
+ *
+ * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
+ *   The entity object.
+ *
+ * @ingroup entity_crud
+ * @see hook_entity_field_values_init()
+ */
+function hook_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
+  if (!$entity->foo->value) {
+    $entity->foo->value = 'some_initial_value';
+  }
+}
+
+/**
  * Exposes "pseudo-field" components on content entities.
  *
  * Field UI's "Manage fields" and "Manage display" pages let users re-order
