diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php
index 0ff36d778d3a8918d70d2e930dda0a2a560a0c2c..7cf493cc9f90b1a2002006f0cc30f7c4202db75c 100644
--- a/core/lib/Drupal/Core/Entity/Field/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Field.php
@@ -224,16 +224,34 @@ public function defaultAccess($operation = 'view', AccountInterface $account = N
    * {@inheritdoc}
    */
   public function applyDefaultValue($notify = TRUE) {
-    if (isset($this->definition['settings']['default_value'])) {
-      $this->setValue($this->definition['settings']['default_value'], $notify);
-    }
-    else {
+    // @todo Remove getDefaultValue() and directly call
+    // FieldDefinition::getFieldDefaultValue() here, once
+    // https://drupal.org/node/2047229 is fixed.
+    $value = $this->getDefaultValue();
+    // NULL or array() mean "no default value", but  0, '0' and the empty string
+    // are valid default values.
+    if (!isset($value) || (is_array($value) && empty($value))) {
       // Create one field item and apply defaults.
       $this->offsetGet(0)->applyDefaultValue(FALSE);
     }
+    else {
+      $this->setValue($value, $notify);
+    }
     return $this;
   }
 
+  /**
+   * Returns the default value for the field.
+   *
+   * @return array
+   *   The default value for the field.
+   */
+  protected function getDefaultValue() {
+    if (isset($this->definition['settings']['default_value'])) {
+      return $this->definition['settings']['default_value'];
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
index 386d47d84f126d1d18352590df7b0f8dab42cb64..b8d1389ef9d5e6bc1debf90d222c610a0cdd99cd 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldDefinitionInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Entity\Field;
 
+use Drupal\Core\Entity\EntityInterface;
+
 /**
  * Defines an interface for entity field definitions.
  *
@@ -156,9 +158,26 @@ public function getFieldCardinality();
    * Currently, required-ness is only enforced at the Form API level in entity
    * edit forms, not during direct API saves.
    *
-   * @var bool
+   * @return bool
    *   TRUE if the field is required.
    */
   public function isFieldRequired();
 
+  /**
+   * Returns the default value for the field in a newly created entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being created.
+   *
+   * @return mixed
+   *   The default value for the field, as accepted by
+   *   Drupal\field\Plugin\Core\Entity\Field::setValue(). This can be either:
+   *   - a literal, in which case it will be assigned to the first property of
+   *     the first item.
+   *   - a numerically indexed array of items, each item being a property/value
+   *     array.
+   *   - NULL or array() for no default value.
+   */
+  public function getFieldDefaultValue(EntityInterface $entity);
+
 }
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
index b147976c9c07b90ece4851300af2cfd6afe2c82c..3732b7365d8abf40f6fe08d7f934b36a3944954d 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EmailItem.php
@@ -52,6 +52,6 @@ public function getPropertyDefinitions() {
    * {@inheritdoc}
    */
   public function isEmpty() {
-    return !isset($this->values['value']) || $this->values['value'] === '';
+    return $this->value === NULL || $this->value === '';
   }
 }
diff --git a/core/modules/field/field.deprecated.inc b/core/modules/field/field.deprecated.inc
index 8c9238e92d6267641bc7b1a2084875ef22867e05..fb97efff89863b0cf1b7e1063f9cd9c9e1758297 100644
--- a/core/modules/field/field.deprecated.inc
+++ b/core/modules/field/field.deprecated.inc
@@ -1188,3 +1188,25 @@ function field_get_items(EntityInterface $entity, $field_name, $langcode = NULL)
   $langcode = field_language($entity, $field_name, $langcode);
   return isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
 }
+
+/**
+ * Helper function to get the default value for a field on an entity.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity for the operation.
+ * @param $field
+ *   The field structure.
+ * @param $instance
+ *   The instance structure.
+ * @param $langcode
+ *   The field language to fill-in with the default value.
+ *
+ * @return array
+ *   The default value for the field.
+ *
+ * @deprecated as of Drupal 8.0. Use
+ *   $instance->getFieldDefaultValue($entity)
+ */
+function field_get_default_value(EntityInterface $entity, $field, $instance, $langcode = NULL) {
+  return $instance->getFieldDefaultValue($entity);
+}
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index efb3fb0fba05503fffd7e9865872f47de05ea23b..c355e678df7aa1ade2ef9ebe2fefc022cf948d21 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -233,44 +233,6 @@ function field_system_info_alter(&$info, $file, $type) {
   }
 }
 
-/**
- * Implements hook_entity_create().
- */
-function field_entity_create(EntityInterface $entity) {
-  $info = $entity->entityInfo();
-  if (!empty($info['fieldable'])) {
-    field_populate_default_values($entity, $entity->language()->id);
-  }
-}
-
-/**
- * Inserts a default value for each entity field not having one.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity for the operation.
- * @param string $langcode
- *   (optional) The field language code to fill-in with the default value.
- *   Defaults to the entity language.
- */
-function field_populate_default_values(EntityInterface $entity, $langcode = NULL) {
-  // Ensure we are working with a BC mode entity.
-  $entity = $entity->getBCEntity();
-
-  $entity_type = $entity->entityType();
-  $langcode = $langcode ?: $entity->language()->id;
-  foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) {
-    $field = field_info_field($field_name);
-    $field_langcode = field_is_translatable($entity_type, $field) ? $langcode : Language::LANGCODE_NOT_SPECIFIED;
-    // We need to preserve existing values.
-    if (empty($entity->{$field_name}) || !array_key_exists($field_langcode, $entity->{$field_name})) {
-      $items = field_get_default_value($entity, $field, $instance, $field_langcode);
-      if (!empty($items)) {
-        $entity->{$field_name}[$field_langcode] = $items;
-      }
-    }
-  }
-}
-
 /**
  * Implements hook_entity_field_info() to define all configured fields.
  */
@@ -492,30 +454,6 @@ function field_sync_field_status() {
   field_cache_clear();
 }
 
-/**
- * Helper function to get the default value for a field on an entity.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity for the operation.
- * @param $field
- *   The field structure.
- * @param $instance
- *   The instance structure.
- * @param $langcode
- *   The field language to fill-in with the default value.
- */
-function field_get_default_value(EntityInterface $entity, $field, $instance, $langcode = NULL) {
-  $items = array();
-  if (!empty($instance['default_value_function'])) {
-    $function = $instance['default_value_function'];
-    $items = $function($entity, $field, $instance, $langcode);
-  }
-  elseif (!empty($instance['default_value'])) {
-    $items = $instance['default_value'];
-  }
-  return $items;
-}
-
 /**
  * Gets or sets administratively defined bundle settings.
  *
diff --git a/core/modules/field/lib/Drupal/field/Entity/Field.php b/core/modules/field/lib/Drupal/field/Entity/Field.php
index cb2d4f0811f380efb2683251f96cf7d1207dfc77..21e01c4a4e46c3e2a0302f62ad0aebcb15712ffa 100644
--- a/core/modules/field/lib/Drupal/field/Entity/Field.php
+++ b/core/modules/field/lib/Drupal/field/Entity/Field.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\field\FieldException;
 use Drupal\field\FieldInterface;
 
@@ -648,6 +649,11 @@ public function isFieldRequired() {
     return FALSE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldDefaultValue(EntityInterface $entity) { }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
index 3d8635b37aeb63c7970d46968d2693e9cb76997c..f99fb1f5c4d34b90ad4060e707a6969b8419f6e3 100644
--- a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\field\FieldException;
 use Drupal\field\FieldInstanceInterface;
 
@@ -582,6 +583,19 @@ public function isFieldRequired() {
     return $this->required;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getFieldDefaultValue(EntityInterface $entity) {
+    if (!empty($this->default_value_function)) {
+      $function = $this->default_value_function;
+      return $function($entity, $this->getField(), $this, $entity->language()->id);
+    }
+    elseif (!empty($this->default_value)) {
+      return $this->default_value;
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
index b61b301714b38f6a5f2891a19a67cc43a3660bc2..1a58ff458c3fbf7b681db84344db2960799bbb42 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php
@@ -72,4 +72,11 @@ public function getConstraints() {
     return $constraints;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultValue() {
+    return $this->getInstance()->getFieldDefaultValue($this->getParent());
+  }
+
 }