diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 0e8e6b8..29b0d31 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -336,11 +336,25 @@ protected function buildBaseFieldDefinitions($entity_type_id) {
     $entity_type = $this->getDefinition($entity_type_id);
     $class = $entity_type->getClass();
 
+    // Retrieve base field definitions and assign them the entity type provider.
     $base_field_definitions = $class::baseFieldDefinitions($entity_type);
+    $provider = $entity_type->getProvider();
+    foreach ($base_field_definitions as $definition) {
+      $definition->setProvider($provider);
+    }
 
-    // Invoke hook.
-    $result = $this->moduleHandler->invokeAll('entity_base_field_info', array($entity_type));
-    $base_field_definitions = NestedArray::mergeDeep($base_field_definitions, $result);
+    // Retrieve base field definitions from modules.
+    foreach ($this->moduleHandler->getImplementations('entity_base_field_info') as $module) {
+      $module_definitions = $this->moduleHandler->invoke($module, 'entity_base_field_info', array($entity_type));
+      if (!empty($module_definitions)) {
+        // Ensure the provider key actually matches the name of the provider
+        // defining the field.
+        foreach ($module_definitions as $field_name => $definition) {
+          $definition->setProvider($module);
+          $base_field_definitions[$field_name] = $definition;
+        }
+      }
+    }
 
     // Automatically set the field name for non-configurable fields.
     foreach ($base_field_definitions as $field_name => $base_field_definition) {
@@ -410,11 +424,24 @@ protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $
     $class = $entity_type->getClass();
 
     // Allow the entity class to override the base fields.
+    $provider = $entity_type->getProvider();
     $bundle_field_definitions = $class::bundleFieldDefinitions($entity_type, $bundle, $base_field_definitions);
+    foreach ($bundle_field_definitions as $definition) {
+      $definition->setProvider($provider);
+    }
 
-    // Invoke 'per bundle' hook.
-    $result = $this->moduleHandler->invokeAll('entity_bundle_field_info', array($entity_type, $bundle, $base_field_definitions));
-    $bundle_field_definitions = NestedArray::mergeDeep($bundle_field_definitions, $result);
+    // Retrieve base field definitions from modules.
+    foreach ($this->moduleHandler->getImplementations('entity_bundle_field_info') as $module) {
+      $module_definitions = $this->moduleHandler->invoke($module, 'entity_bundle_field_info', array($entity_type, $bundle, $base_field_definitions));
+      if (!empty($module_definitions)) {
+        // Ensure the provider key actually matches the name of the provider
+        // defining the field.
+        foreach ($module_definitions as $field_name => $definition) {
+          $definition->setProvider($module);
+          $bundle_field_definitions[$field_name] = $definition;
+        }
+      }
+    }
 
     // Automatically set the field name for non-configurable fields.
     foreach ($bundle_field_definitions as $field_name => $field_definition) {
diff --git a/core/lib/Drupal/Core/Field/FieldDefinition.php b/core/lib/Drupal/Core/Field/FieldDefinition.php
index 3968624..6cfec74 100644
--- a/core/lib/Drupal/Core/Field/FieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/FieldDefinition.php
@@ -151,6 +151,26 @@ public function setSetting($setting_name, $value) {
   /**
    * {@inheritdoc}
    */
+  public function getProvider() {
+    return $this->definition['provider'];
+  }
+
+  /**
+   * Sets the name of the provider of this field.
+   *
+   * @param string $provider
+   *   The provider name to set.
+   *
+   * @return $this
+   */
+  public function setProvider($provider) {
+    $this->definition['provider'] = $provider;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isTranslatable() {
     return !empty($this->definition['translatable']);
   }
@@ -446,4 +466,25 @@ public static function getReservedColumns() {
     return array('deleted');
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function hasCustomStorage() {
+    return !empty($this->definition['custom_storage']);
+  }
+
+  /**
+   * Sets the storage behavior for this field.
+   *
+   * @param bool $custom_storage
+   *   Pass FALSE if the storage controller takes care of storing the field,
+   *   TRUE otherwise.
+   *
+   * @return $this
+   */
+  public function setCustomStorage($custom_storage) {
+    $this->definition['custom_storage'] = $custom_storage;
+    return $this;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
index 06de3c6..b0eab20 100644
--- a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
@@ -104,6 +104,14 @@ public function getSettings();
   public function getSetting($setting_name);
 
   /**
+   * Returns the name of the provider of this field.
+   *
+   * @return string
+   *   The provider name; e.g., the module name.
+   */
+  public function getProvider();
+
+  /**
    * Returns whether the field is translatable.
    *
    * @return bool
@@ -328,4 +336,17 @@ public function getSchema();
    */
   public function getColumns();
 
+  /**
+   * Returns the storage behavior for this field.
+   *
+   * Indicates whether the entity type's storage controller should take care of
+   * storing the field values or whether it is handled separately; e.g. by the
+   * module providing the field.
+   *
+   * @return bool
+   *   FALSE if the storage controller takes care of storing the field, TRUE
+   *   otherwise.
+   */
+  public function hasCustomStorage();
+
 }
diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php
index ae8d4fc..971e246 100644
--- a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php
@@ -478,6 +478,13 @@ public function getSchema() {
   /**
    * {@inheritdoc}
    */
+  public function hasCustomStorage() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getColumns() {
     $schema = $this->getSchema();
     // A typical use case for the method is to iterate on the columns, while
@@ -576,6 +583,13 @@ public function setTranslatable($translatable) {
   /**
    * {@inheritdoc}
    */
+  public function getProvider() {
+    return 'field';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getLabel() {
     return $this->label();
   }
diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
index 384d76f..e249355 100644
--- a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
@@ -501,6 +501,13 @@ public function getSetting($setting_name) {
   /**
    * {@inheritdoc}
    */
+  public function getProvider() {
+    return $this->field->getProvider();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isTranslatable() {
     return $this->field->translatable;
   }
@@ -758,4 +765,11 @@ public function getColumns() {
     return $this->field->getColumns();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function hasCustomStorage() {
+    return $this->field->hasCustomStorage();
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
index 4414904..b58336f 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
@@ -553,6 +553,38 @@ public function testGetBaseFieldDefinitionsInvalidDefinition() {
   }
 
   /**
+   * Tests that getFieldDefinitions() method sets the 'provider' definition key.
+   *
+   * @covers ::getFieldDefinitions()
+   */
+  public function testGetFieldDefinitionsProvider() {
+    $this->setUpEntityWithFieldDefinition(TRUE);
+
+    $module = 'entity_manager_test_module';
+
+    $field_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinitionInterface')
+      ->getMock();
+
+    // We expect two calls as the field definition will be returned from both
+    // base and bundle entity field info hook implementations.
+    $field_definition
+      ->expects($this->exactly(2))
+      ->method('setProvider')
+      ->with($this->matches($module));
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getImplementations')
+      ->will($this->returnValue(array($module)));
+
+    $this->moduleHandler->expects($this->any())
+      ->method('invoke')
+      ->with($this->matches($module))
+      ->will($this->returnValue(array($field_definition)));
+
+    $this->entityManager->getFieldDefinitions('test_entity_type', 'test_bundle');
+  }
+
+  /**
    * Prepares an entity that defines a field definition.
    *
    * @param bool $custom_invoke_all
@@ -587,11 +619,12 @@ protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $f
       ->method('bundleFieldDefinitions')
       ->will($this->returnValue(array()));
 
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
     $this->moduleHandler->expects($this->any())
       ->method('alter');
     if (!$custom_invoke_all) {
       $this->moduleHandler->expects($this->any())
-        ->method('invokeAll')
+        ->method('getImplementations')
         ->will($this->returnValue(array()));
     }
 
diff --git a/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php b/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php
index 5ddd924..e58bb61 100644
--- a/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php
@@ -194,4 +194,26 @@ public function testFieldRequired() {
     $this->assertFalse($definition->isRequired());
   }
 
+  /**
+   * Tests provider.
+   */
+  public function testFieldProvider() {
+    $definition = FieldDefinition::create($this->fieldType);
+    $provider = $this->randomName();
+    $definition->setProvider($provider);
+    $this->assertEquals($provider, $definition->getProvider());
+  }
+
+  /**
+   * Tests custom storage.
+   */
+  public function testCustomStorage() {
+    $definition = FieldDefinition::create($this->fieldType);
+    $this->assertFalse($definition->hasCustomStorage());
+    $definition->setCustomStorage(TRUE);
+    $this->assertTrue($definition->hasCustomStorage());
+    $definition->setCustomStorage(FALSE);
+    $this->assertFalse($definition->hasCustomStorage());
+  }
+
 }
