diff --git a/core/lib/Drupal/Core/Field/FieldDefinition.php b/core/lib/Drupal/Core/Field/FieldDefinition.php
index 882d086..3a8b495 100644
--- a/core/lib/Drupal/Core/Field/FieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/FieldDefinition.php
@@ -188,6 +188,69 @@ public function setPropertyConstraints($name, array $constraints) {
   }
 
   /**
+   * Sets the display options for the field in forms or rendered entities.
+   *
+   * This enables generic rendering of the field with widgets / formatters,
+   * including automated support for "In place editing", and with optional
+   * configurability in the "Manage display" / "Manage form display" UI screens.
+   *
+   * Unless this method is called, the field remains invisible (or requires
+   * ad-hoc rendering logic).
+   *
+   * @param string $display_context
+   *   The display context. Either 'view' or 'form'.
+   * @param array $options
+   *   An array of display options. Refer to
+   *   \Drupal\Core\Field\FieldDefinitionInterface::getDisplayOptions() for
+   *   a list of supported keys. The options should include at least a 'weight',
+   *   or specify 'type' = 'hidden'. The 'default_widget' / 'default_formatter'
+   *   for the field type will be used if no 'type' is specified.
+   *
+   * @return static
+   *   The object itself for chaining.
+   */
+  public function setDisplayOptions($display_context, array $options) {
+    $this->definition['display'][$display_context]['options'] = $options;
+    return $this;
+  }
+
+  /**
+   * Sets whether the display for the field can be configured in the UI.
+   *
+   * @param string $display_context
+   *   The display context. Either 'view' or 'form'.
+   * @param bool $configurable
+   *   Whether the display options can be configured in the "Manage display" /
+   *   "Manage form display" UI screens. If TRUE, the options specified via
+   *   getDisplayOptions() act as defaults.
+   *
+   * @return static
+   *   The object itself for chaining.
+   */
+  public function setDisplayConfigurable($display_context, $configurable) {
+    // If no explicit display options have been specified, default to 'hidden'.
+    if (empty($this->definition['display'][$display_context])) {
+      $this->definition['display'][$display_context]['options'] = array('type' => 'hidden');
+    }
+    $this->definition['display'][$display_context]['configurable'] = $configurable;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDisplayOptions($display_context) {
+    return isset($this->definition['display'][$display_context]['options']) ? $this->definition['display'][$display_context]['options'] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isDisplayConfigurable($display_context) {
+    return isset($this->definition['display'][$display_context]['configurable']) ? $this->definition['display'][$display_context]['configurable'] : FALSE;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function isConfigurable() {
diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
index 76f0ef9..29222a4 100644
--- a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php
@@ -127,7 +127,7 @@ public function getPropertyNames();
   public function isTranslatable();
 
   /**
-   * Determines whether the field is configurable via field.module.
+   * Returns whether the field is configurable via field.module.
    *
    * @return bool
    *   TRUE if the field is configurable.
@@ -135,6 +135,48 @@ public function isTranslatable();
   public function isConfigurable();
 
   /**
+   * Returns whether the display for the field can be configured in the UI.
+   *
+   * @param string $display_context
+   *   The display context. Either 'view' or 'form'.
+   *
+   * @return bool
+   *   TRUE if the display for this field is configurable in the given context.
+   */
+  public function isDisplayConfigurable($display_context);
+
+  /**
+   * Returns the default display options for the field.
+   *
+   * If the field's display is configurable, the returned display options act
+   * as default values and may be overridden via the respective EntityDisplay.
+   * Otherwise, the display options will be applied to entity displays as is.
+   *
+   * @param string $display_context
+   *   The display context. Either 'view' or 'form'.
+   *
+   * @return array|null
+   *   The array of display options for the field, or NULL if the field is not
+   *   displayed. The following key/value pairs may be present:
+   *   - label: (string) Position of the field label. The default 'field' theme
+   *     implementation supports the values 'inline', 'above' and 'hidden'.
+   *     Defaults to 'above'. Only applies to 'view' context.
+   *   - type: (string) The plugin (widget or formatter depending on
+   *     $display_context) to use, or 'hidden'. If not specified or if the
+   *     requested plugin is unknown, the 'default_widget' / 'default_formatter'
+   *     for the field type will be used.
+   *   - settings: (array) Settings for the plugin specified above. The default
+   *     settings for the plugin will be used for settings left unspecified.
+   *   - weight: (float) The weight of the element. Not needed if 'type' is
+   *     'hidden'.
+   *   The defaults of the various display options above get applied by the used
+   *   entity display.
+   *
+   * @see \Drupal\Core\Entity\Display\EntityDisplayInterface
+   */
+  public function getDisplayOptions($display_context);
+
+  /**
    * Determines whether the field is queryable via QueryInterface.
    *
    * @return bool
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php
index adf6e8a..846868e 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentPagerTest.php
@@ -281,7 +281,7 @@ function testTwoPagers() {
       ->setComponent('comment_2', array(
         'label' => 'hidden',
         'type' => 'comment_default',
-        'weight' => 20,
+        'weight' => 30,
         'settings' => array(
           'pager_id' => 1,
         )
diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php
index 70deb3e..baf1cbd 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityDisplay.php
@@ -33,9 +33,13 @@ class EntityDisplay extends EntityDisplayBase implements EntityViewDisplayInterf
   /**
    * {@inheritdoc}
    */
+  protected $displayContext = 'view';
+
+  /**
+   * {@inheritdoc}
+   */
   public function __construct(array $values, $entity_type) {
     $this->pluginManager = \Drupal::service('plugin.manager.field.formatter');
-    $this->displayContext = 'display';
 
     parent::__construct($values, $entity_type);
   }
diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php
index a21a849..26de1db 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormDisplay.php
@@ -33,9 +33,13 @@ class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayIn
   /**
    * {@inheritdoc}
    */
+  protected $displayContext = 'form';
+
+  /**
+   * {@inheritdoc}
+   */
   public function __construct(array $values, $entity_type) {
     $this->pluginManager = \Drupal::service('plugin.manager.field.widget');
-    $this->displayContext = 'form';
 
     parent::__construct($values, $entity_type);
   }
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
index 310520c..afda40a 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
@@ -8,8 +8,10 @@
 namespace Drupal\entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
-use Drupal\Core\Entity\ContentEntityInterface;
 
 /**
  * Base class for config entity types that store configuration for entity forms
@@ -46,15 +48,11 @@
   public $bundle;
 
   /**
-   * A partial entity, created via _field_create_entity_from_ids() from
-   * $targetEntityType and $bundle.
+   * A list of field definitions eligible for configuration in this display.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
-   *
-   * @todo Remove when getFieldDefinition() is fixed to not need it.
-   *   https://drupal.org/node/2114707
+   * @var \Drupal\Core\Field\FieldDefinitionInterface[]
    */
-  private $targetEntity;
+  protected $fieldDefinitions;
 
   /**
    * View or form mode to be displayed.
@@ -79,6 +77,13 @@
   protected $content = array();
 
   /**
+   * List of components that are set to be hidden.
+   *
+   * @var array
+   */
+  protected $hidden = array();
+
+  /**
    * The original view or form mode that was requested (case of view/form modes
    * being configured to fall back to the 'default' display).
    *
@@ -130,6 +135,8 @@ public function __construct(array $values, $entity_type) {
     parent::__construct($values, $entity_type);
 
     $this->originalMode = $this->mode;
+
+    $this->init();
   }
 
   /**
@@ -142,15 +149,19 @@ public function id() {
   /**
    * {@inheritdoc}
    */
-  public function save() {
-    $return = parent::save();
+  public function preSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
+    // Sort elements by weight before saving.
+    uasort($this->content, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
+  }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
     // Reset the render cache for the target entity type.
     if (\Drupal::entityManager()->hasController($this->targetEntityType, 'view_builder')) {
       \Drupal::entityManager()->getViewBuilder($this->targetEntityType)->resetCache();
     }
-
-    return $return;
   }
 
   /**
@@ -164,16 +175,71 @@ public function getExportProperties() {
       'bundle',
       'mode',
       'content',
+      'hidden',
       'status',
     );
     $properties = array();
     foreach ($names as $name) {
       $properties[$name] = $this->get($name);
     }
+
+    // Do not store options for fields whose display is not set to be
+    // configurable.
+    foreach ($this->getFieldDefinitions() as $field_name => $definition) {
+      if (!$definition->isDisplayConfigurable($this->displayContext)) {
+        unset($properties['content'][$field_name]);
+        unset($properties['hidden'][$field_name]);
+      }
+    }
+
     return $properties;
   }
 
   /**
+   * Initializes the display.
+   *
+   * This fills in default options for components:
+   * - that are not explicitly known as either "visible" or "hidden" in the
+   *   display,
+   * - or that are not supposed to be configurable.
+   */
+  protected function init() {
+    // Fill in defaults for extra fields.
+    $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, ($this->displayContext == 'view' ? 'display' : $this->displayContext));
+    foreach ($extra_fields as $name => $definition) {
+      if (!isset($this->content[$name]) && !isset($this->hidden[$name])) {
+        // Extra fields are visible by default unless they explicitly say so.
+        if (!isset($definition['visible']) || $definition['visible'] == TRUE) {
+          $this->content[$name] = array(
+            'weight' => $definition['weight']
+          );
+        }
+        else {
+          $this->hidden[$name] = TRUE;
+        }
+      }
+    }
+
+    // Fill in defaults for fields.
+    $fields = $this->getFieldDefinitions();
+    foreach ($fields as $name => $definition) {
+      if (!$definition->isDisplayConfigurable($this->displayContext) || (!isset($this->content[$name]) && !isset($this->hidden[$name]))) {
+        $options = $definition->getDisplayOptions($this->displayContext);
+
+        if (!empty($options['type']) && $options['type'] == 'hidden') {
+          $this->hidden[$name] = TRUE;
+        }
+        elseif ($options) {
+          $this->content[$name] = $this->pluginManager->prepareConfiguration($definition->getType(), $options);
+        }
+        // Note: (base) fields that do not specify display options are not
+        // tracked in the display at all, in order to avoid cluttering the
+        // configuration that gets saved back.
+      }
+    }
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function createCopy($mode) {
@@ -186,64 +252,14 @@ public function createCopy($mode) {
    * {@inheritdoc}
    */
   public function getComponents() {
-    $result = array();
-    foreach ($this->content as $name => $options) {
-      if (!isset($options['visible']) || $options['visible'] == TRUE) {
-        unset($options['visible']);
-        $result[$name] = $options;
-      }
-    }
-    return $result;
+    return $this->content;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getComponent($name) {
-    // Until https://drupal.org/node/2144919 allows base fields to be configured
-    // in the UI, many base fields are also still registered as "extra fields"
-    // to keep appearing in the "Manage (form) display" screens.
-    // - Field UI still treats them as "base fields", saving only the weight
-    //   and visibility flag in the EntityDisplay.
-    // - For some of them (e.g. node title), the custom rendering code has been
-    //   removed in favor of regular widgets/formatters. Their display options
-    //   are "upgraded" to those of a field (widget/formatter + settings) at
-    //   runtime using hook_entity_display_alter().
-    // The getComponent() / setComponent() methods handle this by treating
-    // components as "extra fields" if they are registered as such, *and* if
-    // their display options contain no 'type' entry specifying a widget or
-    // formatter.
-    // @todo Cleanup after https://drupal.org/node/2144919 is fixed.
-    $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, $this->displayContext);
-    if (isset($extra_fields[$name]) && !isset($this->content[$name]['type'])) {
-      // If we have explicit settings, return an array or NULL depending on
-      // visibility.
-      if (isset($this->content[$name])) {
-        if ($this->content[$name]['visible']) {
-          return array(
-            'weight' => $this->content[$name]['weight'],
-          );
-        }
-        else {
-          return NULL;
-        }
-      }
-
-      // If no explicit settings for the extra field, look at the default
-      // visibility in its definition.
-      $definition = $extra_fields[$name];
-      if (!isset($definition['visible']) || $definition['visible'] == TRUE) {
-        return array(
-          'weight' => $definition['weight']
-        );
-      }
-      else {
-        return NULL;
-      }
-    }
-    elseif (isset($this->content[$name])) {
-      return $this->content[$name];
-    }
+    return isset($this->content[$name]) ? $this->content[$name] : NULL;
   }
 
   /**
@@ -255,20 +271,15 @@ public function setComponent($name, array $options = array()) {
       $max = $this->getHighestWeight();
       $options['weight'] = isset($max) ? $max + 1 : 0;
     }
-    // See remark in getComponent().
-    // @todo Cleanup after https://drupal.org/node/2144919 is fixed.
-    $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, $this->displayContext);
-    if (isset($extra_fields[$name]) && !isset($options['type'])) {
-      $options['visible'] = TRUE;
-    }
-    elseif ($field_definition = $this->getFieldDefinition($name)) {
+
+    // For a field, fill in default options.
+    if ($field_definition = $this->getFieldDefinition($name)) {
       $options = $this->pluginManager->prepareConfiguration($field_definition->getType(), $options);
     }
 
-    // Clear the persisted plugin, if any.
-    unset($this->plugins[$name]);
-
     $this->content[$name] = $options;
+    unset($this->hidden[$name]);
+    unset($this->plugins[$name]);
 
     return $this;
   }
@@ -277,22 +288,8 @@ public function setComponent($name, array $options = array()) {
    * {@inheritdoc}
    */
   public function removeComponent($name) {
-    // See remark in getComponent().
-    // @todo Cleanup after https://drupal.org/node/2144919 is fixed.
-    $extra_fields = field_info_extra_fields($this->targetEntityType, $this->bundle, $this->displayContext);
-    if (isset($extra_fields[$name]) && !isset($this->content[$name]['type'])) {
-      // 'Extra fields' are exposed in hooks and can appear at any given time.
-      // Therefore we store extra fields that are explicitly being hidden, so
-      // that we can differenciate with those that are simply not configured
-      // yet.
-      $this->content[$name] = array(
-        'visible' => FALSE,
-      );
-    }
-    else {
-      unset($this->content[$name]);
-    }
-
+    $this->hidden[$name] = TRUE;
+    unset($this->content[$name]);
     unset($this->plugins[$name]);
 
     return $this;
@@ -321,14 +318,38 @@ public function getHighestWeight() {
    * Returns the field definition of a field.
    */
   protected function getFieldDefinition($field_name) {
-    // @todo Replace this entire implementation with
-    //   \Drupal::entityManager()->getFieldDefinition() when it can hand the
-    //   $instance objects - https://drupal.org/node/2114707
-    if (!isset($this->targetEntity)) {
-      $this->targetEntity = _field_create_entity_from_ids((object) array('entity_type' => $this->targetEntityType, 'bundle' => $this->bundle, 'entity_id' => NULL));
-    }
-    if (($this->targetEntity instanceof ContentEntityInterface) && $this->targetEntity->hasField($field_name)) {
-      return $this->targetEntity->get($field_name)->getFieldDefinition();
+    $definitions = $this->getFieldDefinitions();
+    return isset($definitions[$field_name]) ? $definitions[$field_name] : NULL;
+  }
+
+  /**
+   * Returns the definitions of the fields that are candidate for display.
+   */
+  protected function getFieldDefinitions() {
+    if (!isset($this->fieldDefinitions)) {
+      // @todo Replace this with \Drupal::entityManager()->getFieldDefinition()
+      //   when it can hand the $instance objects (and then reconsider the
+      //   $this->fieldDefinitions static cache ?)
+      //   https://drupal.org/node/2114707
+      $entity_manager = \Drupal::entityManager();
+      $entity_info = $entity_manager->getDefinition($this->targetEntityType);
+      $definitions = array();
+      if ($entity_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface')) {
+        $entity = _field_create_entity_from_ids((object) array('entity_type' => $this->targetEntityType, 'bundle' => $this->bundle, 'entity_id' => NULL));
+        foreach ($entity as $field_name => $items) {
+          $definitions[$field_name] = $items->getFieldDefinition();
+        }
+      }
+
+      // The display only cares about fields that specify display options.
+      // Discard base fields that are not rendered through formatters / widgets.
+      $display_context = $this->displayContext;
+      $this->fieldDefinitions = array_filter($definitions, function (FieldDefinitionInterface $definition) use ($display_context) {
+        return $definition->getDisplayOptions($display_context);
+      });
     }
+
+    return $this->fieldDefinitions;
   }
+
 }
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
index bc4e144..28dc5eb 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
@@ -14,7 +14,7 @@
  */
 class EntityDisplayTest extends DrupalUnitTestBase {
 
-  public static $modules = array('entity', 'field', 'entity_test', 'user');
+  public static $modules = array('entity', 'field', 'entity_test', 'user', 'text');
 
   public static function getInfo() {
     return array(
@@ -109,9 +109,10 @@ public function testEntityGetDisplay() {
    * Tests the behavior of a field component within an EntityDisplay object.
    */
   public function testExtraFieldComponent() {
+    entity_test_create_bundle('bundle_with_extra_fields');
     $display = entity_create('entity_display', array(
       'targetEntityType' => 'entity_test',
-      'bundle' => 'entity_test',
+      'bundle' => 'bundle_with_extra_fields',
       'mode' => 'default',
     ));
 
@@ -133,12 +134,6 @@ public function testExtraFieldComponent() {
   public function testFieldComponent() {
     $this->enableModules(array('field_test'));
 
-    $display = entity_create('entity_display', array(
-      'targetEntityType' => 'entity_test',
-      'bundle' => 'entity_test',
-      'mode' => 'default',
-    ));
-
     $field_name = 'test_field';
     // Create a field and an instance.
     $field = entity_create('field_entity', array(
@@ -154,23 +149,29 @@ public function testFieldComponent() {
     ));
     $instance->save();
 
+    $display = entity_create('entity_display', array(
+      'targetEntityType' => 'entity_test',
+      'bundle' => 'entity_test',
+      'mode' => 'default',
+    ));
+
     // Check that providing no options results in default values being used.
     $display->setComponent($field_name);
     $field_type_info = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field->type);
     $default_formatter = $field_type_info['default_formatter'];
-    $formatter_settings =  \Drupal::service('plugin.manager.field.formatter')->getDefinition($default_formatter);
+    $formatter_settings =  \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings($default_formatter);
     $expected = array(
       'weight' => 0,
       'label' => 'above',
       'type' => $default_formatter,
-      'settings' => $formatter_settings['settings'],
+      'settings' => $formatter_settings,
     );
     $this->assertEqual($display->getComponent($field_name), $expected);
 
     // Check that the getFormatter() method returns the correct formatter plugin.
     $formatter = $display->getRenderer($field_name);
     $this->assertEqual($formatter->getPluginId(), $default_formatter);
-    $this->assertEqual($formatter->getSettings(), $formatter_settings['settings']);
+    $this->assertEqual($formatter->getSettings(), $formatter_settings);
 
     // Check that the formatter is statically persisted, by assigning an
     // arbitrary property and reading it back.
@@ -200,6 +201,65 @@ public function testFieldComponent() {
   }
 
   /**
+   * Tests the behavior of a field component for a base field.
+   */
+  public function testBaseFieldComponent() {
+    $display = entity_create('entity_display', array(
+      'targetEntityType' => 'entity_test_base_field_display',
+      'bundle' => 'entity_test_base_field_display',
+      'mode' => 'default',
+    ));
+
+    // Check that default options are correctly filled in.
+    $formatter_settings =  \Drupal::service('plugin.manager.field.formatter')->getDefaultSettings('text_default');
+    $expected = array(
+      'test_no_display' => NULL,
+      'test_display_configurable' => array(
+        'label' => 'above',
+        'type' => 'text_default',
+        'settings' => $formatter_settings,
+        'weight' => 10,
+      ),
+      'test_display_non_configurable' => array(
+        'label' => 'above',
+        'type' => 'text_default',
+        'settings' => $formatter_settings,
+        'weight' => 11,
+      ),
+    );
+    foreach ($expected as $field_name => $options) {
+      $this->assertEqual($display->getComponent($field_name), $options);
+    }
+
+    // Check that saving the display only writes data for fields whose display
+    // is configurable.
+    $display->save();
+    $config = \Drupal::config('entity.display.' . $display->id());
+    $data = $config->get();
+    $this->assertFalse(isset($data['content']['test_no_display']));
+    $this->assertFalse(isset($data['hidden']['test_no_display']));
+    $this->assertEqual($data['content']['test_display_configurable'], $expected['test_display_configurable']);
+    $this->assertFalse(isset($data['content']['test_display_non_configurable']));
+    $this->assertFalse(isset($data['hidden']['test_display_non_configurable']));
+
+    // Check that defaults are correctly filled when loading the display.
+    $display = entity_load('entity_display', $display->id());
+    foreach ($expected as $field_name => $options) {
+      $this->assertEqual($display->getComponent($field_name), $options);
+    }
+
+    // Check that data manually written for fields whose display is not
+    // configurable is discarded when loading the display.
+    $data['content']['test_display_non_configurable'] = $expected['test_display_non_configurable'];
+    $data['content']['test_display_non_configurable']['weight']++;
+    $config->setData($data)->save();
+    $display = entity_load('entity_display', $display->id());
+    foreach ($expected as $field_name => $options) {
+      $this->assertEqual($display->getComponent($field_name), $options);
+    }
+  }
+
+  /**
    * Tests renaming and deleting a bundle.
    */
   public function testRenameDeleteBundle() {
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php
index 5ee2a89..dc1d93e 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php
@@ -14,7 +14,7 @@
  */
 class EntityFormDisplayTest extends DrupalUnitTestBase {
 
-  public static $modules = array('entity', 'field', 'entity_test', 'user');
+  public static $modules = array('entity', 'field', 'entity_test', 'user', 'text');
 
   public static function getInfo() {
     return array(
@@ -55,43 +55,43 @@ public function testEntityGetFromDisplay() {
   public function testFieldComponent() {
     $this->enableModules(array('field_test'));
 
+    // Create a field and an instance.
+    $field_name = 'test_field';
+    $field = entity_create('field_entity', array(
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
+      'type' => 'test_field'
+    ));
+    $field->save();
+    $instance = entity_create('field_instance', array(
+      'field_name' => $field_name,
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+    ));
+    $instance->save();
+
     $form_display = entity_create('entity_form_display', array(
       'targetEntityType' => 'entity_test',
       'bundle' => 'entity_test',
       'mode' => 'default',
     ));
 
-    // Create a field and an instance.
-    $field_name = 'test_field';
-    $field = entity_create('field_entity', array(
-      'name' => $field_name,
-      'entity_type' => 'entity_test',
-      'type' => 'test_field'
-    ));
-    $field->save();
-    $instance = entity_create('field_instance', array(
-      'field_name' => $field_name,
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
-    ));
-    $instance->save();
-
     // Check that providing no options results in default values being used.
     $form_display->setComponent($field_name);
     $field_type_info = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field->type);
     $default_widget = $field_type_info['default_widget'];
-    $widget_settings = \Drupal::service('plugin.manager.field.widget')->getDefinition($default_widget);
+    $widget_settings = \Drupal::service('plugin.manager.field.widget')->getDefaultSettings($default_widget);
     $expected = array(
       'weight' => 0,
       'type' => $default_widget,
-      'settings' => $widget_settings['settings'],
+      'settings' => $widget_settings,
     );
     $this->assertEqual($form_display->getComponent($field_name), $expected);
 
     // Check that the getWidget() method returns the correct widget plugin.
     $widget = $form_display->getRenderer($field_name);
     $this->assertEqual($widget->getPluginId(), $default_widget);
-    $this->assertEqual($widget->getSettings(), $widget_settings['settings']);
+    $this->assertEqual($widget->getSettings(), $widget_settings);
 
     // Check that the widget is statically persisted, by assigning an
     // arbitrary property and reading it back.
@@ -120,6 +120,64 @@ public function testFieldComponent() {
     $this->assertEqual($widget->getPluginId(), $default_widget);
   }
 
+
+  /**
+   * Tests the behavior of a field component for a base field.
+   */
+  public function testBaseFieldComponent() {
+    $display = entity_create('entity_form_display', array(
+      'targetEntityType' => 'entity_test_base_field_display',
+      'bundle' => 'entity_test_base_field_display',
+      'mode' => 'default',
+    ));
+
+    // Check that default options are correctly filled in.
+    $formatter_settings =  \Drupal::service('plugin.manager.field.widget')->getDefaultSettings('text_textfield');
+    $expected = array(
+      'test_no_display' => NULL,
+      'test_display_configurable' => array(
+        'type' => 'text_textfield',
+        'settings' => $formatter_settings,
+        'weight' => 10,
+      ),
+      'test_display_non_configurable' => array(
+        'type' => 'text_textfield',
+        'settings' => $formatter_settings,
+        'weight' => 11,
+      ),
+    );
+    foreach ($expected as $field_name => $options) {
+      $this->assertEqual($display->getComponent($field_name), $options);
+    }
+
+    // Check that saving the display only writes data for fields whose display
+    // is configurable.
+    $display->save();
+    $config = \Drupal::config('entity.form_display.' . $display->id());
+    $data = $config->get();
+    $this->assertFalse(isset($data['content']['test_no_display']));
+    $this->assertFalse(isset($data['hidden']['test_no_display']));
+    $this->assertEqual($data['content']['test_display_configurable'], $expected['test_display_configurable']);
+    $this->assertFalse(isset($data['content']['test_display_non_configurable']));
+    $this->assertFalse(isset($data['hidden']['test_display_non_configurable']));
+
+    // Check that defaults are correctly filled when loading the display.
+    $display = entity_load('entity_form_display', $display->id());
+    foreach ($expected as $field_name => $options) {
+      $this->assertEqual($display->getComponent($field_name), $options);
+    }
+
+    // Check that data manually written for fields whose display is not
+    // configurable is discarded when loading the display.
+    $data['content']['test_display_non_configurable'] = $expected['test_display_non_configurable'];
+    $data['content']['test_display_non_configurable']['weight']++;
+    $config->setData($data)->save();
+    $display = entity_load('entity_form_display', $display->id());
+    foreach ($expected as $field_name => $options) {
+      $this->assertEqual($display->getComponent($field_name), $options);
+    }
+  }
+
   /**
    * Tests deleting field instance.
    */
diff --git a/core/modules/field/lib/Drupal/field/Entity/Field.php b/core/modules/field/lib/Drupal/field/Entity/Field.php
index b127979..476df16 100644
--- a/core/modules/field/lib/Drupal/field/Entity/Field.php
+++ b/core/modules/field/lib/Drupal/field/Entity/Field.php
@@ -628,6 +628,21 @@ public function isConfigurable() {
   /**
    * {@inheritdoc}
    */
+  public function isDisplayConfigurable($context) {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDisplayOptions($display_context) {
+    // Hide configurable fields by default.
+    return array('type' => 'hidden');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isQueryable() {
     return TRUE;
   }
diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
index 7c2e381..79fd0e9 100644
--- a/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstance.php
@@ -586,6 +586,21 @@ public function isConfigurable() {
   /**
    * {@inheritdoc}
    */
+  public function isDisplayConfigurable($context) {
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDisplayOptions($display_context) {
+    // Hide configurable fields by default.
+    return array('type' => 'hidden');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isQueryable() {
     return TRUE;
   }
@@ -681,4 +696,5 @@ public function getItemDefinition() {
     }
     return $this->itemDefinition;
   }
+
 }
diff --git a/core/modules/field_ui/field_ui.api.php b/core/modules/field_ui/field_ui.api.php
index 176993d..255ce85 100644
--- a/core/modules/field_ui/field_ui.api.php
+++ b/core/modules/field_ui/field_ui.api.php
@@ -20,8 +20,7 @@
  * @param $context
  *   An associative array with the following elements:
  *   - formatter: The formatter object.
- *   - field: The field structure being configured.
- *   - instance: The instance structure being configured.
+ *   - field_definition: The field definition.
  *   - view_mode: The view mode being configured.
  *   - form: The (entire) configuration form array.
  *
@@ -49,8 +48,7 @@ function hook_field_formatter_settings_form_alter(&$element, &$form_state, $cont
  * @param array $context
  *   An associative array with the following elements:
  *   - formatter: The formatter object.
- *   - field: The field structure being configured.
- *   - instance: The instance structure being configured.
+ *   - field_definition: The field definition.
  *   - form_mode: The form mode being configured.
  *   - form: The (entire) configuration form array.
  *
@@ -75,8 +73,7 @@ function hook_field_widget_settings_form_alter(&$element, &$form_state, $context
  * @param $context
  *   An associative array with the following elements:
  *   - formatter: The formatter object.
- *   - field: The field structure being configured.
- *   - instance: The instance structure being configured.
+ *   - field_definition: The field definition.
  *   - view_mode: The view mode being configured.
  *
  * @see \Drupal\field_ui\DisplayOverView.
@@ -99,8 +96,7 @@ function hook_field_formatter_settings_summary_alter(&$summary, $context) {
  * @param array $context
  *   An associative array with the following elements:
  *   - widget: The widget object.
- *   - field: The field structure being configured.
- *   - instance: The instance structure being configured.
+ *   - field_definition: The field definition.
  *   - form_mode: The form mode being configured.
  *
  * @see \Drupal\field_ui\FormDisplayOverView.
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
index 3ace025..a7444d7 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\field_ui;
 
-use Drupal\field\FieldInstanceInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -19,6 +19,11 @@ class DisplayOverview extends DisplayOverviewBase {
   /**
    * {@inheritdoc}
    */
+  protected $displayContext = 'view';
+
+  /**
+   * {@inheritdoc}
+   */
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.manager'),
@@ -48,15 +53,17 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
   /**
    * {@inheritdoc}
    */
-  protected function buildFieldRow($field_id, FieldInstanceInterface $instance, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
-    $field_row = parent::buildFieldRow($field_id, $instance, $entity_display, $form, $form_state);
-    $display_options = $entity_display->getComponent($field_id);
+  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
+    $field_row = parent::buildFieldRow($field_definition, $entity_display, $form, $form_state);
+
+    $field_name = $field_definition->getName();
+    $display_options = $entity_display->getComponent($field_name);
 
     // Insert the label column.
     $label = array(
       'label' => array(
         '#type' => 'select',
-        '#title' => $this->t('Label display for @title', array('@title' => $instance->getLabel())),
+        '#title' => $this->t('Label display for @title', array('@title' => $field_definition->getLabel())),
         '#title_display' => 'invisible',
         '#options' => $this->getFieldLabelOptions(),
         '#default_value' => $display_options ? $display_options['label'] : 'above',
@@ -67,9 +74,9 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
     $field_row = array_slice($field_row, 0, $label_position, TRUE) + $label + array_slice($field_row, $label_position, count($field_row) - 1, TRUE);
 
     // Update the (invisible) title of the 'plugin' column.
-    $field_row['plugin']['#title'] = $this->t('Formatter for @title', array('@title' => $instance->getLabel()));
-    if (!empty($field_row['plugin']['settings_edit_form'])) {
-      $plugin_type_info = $entity_display->getRenderer($field_id)->getPluginDefinition();
+    $field_row['plugin']['#title'] = $this->t('Formatter for @title', array('@title' => $field_definition->getLabel()));
+    if (!empty($field_row['plugin']['settings_edit_form']) && ($plugin = $entity_display->getRenderer($field_name))) {
+      $plugin_type_info = $plugin->getPluginDefinition();
       $field_row['plugin']['settings_edit_form']['label']['#markup'] = $this->t('Format settings:') . ' <span class="plugin-name">' . $plugin_type_info['label'] . '</span>';
     }
 
@@ -104,19 +111,12 @@ protected function getEntityDisplay($mode) {
   /**
    * {@inheritdoc}
    */
-  protected function getExtraFields() {
-    return field_info_extra_fields($this->entity_type, $this->bundle, 'display');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getPlugin($instance, $configuration) {
+  protected function getPlugin(FieldDefinitionInterface $field_definition, $configuration) {
     $plugin = NULL;
 
     if ($configuration && $configuration['type'] != 'hidden') {
       $plugin = $this->pluginManager->getInstance(array(
-        'field_definition' => $instance,
+        'field_definition' => $field_definition,
         'view_mode' => $this->mode,
         'configuration' => $configuration
       ));
@@ -190,11 +190,10 @@ protected function getFieldLabelOptions() {
   /**
    * {@inheritdoc}
    */
-  protected function alterSettingsForm(array &$settings_form, $plugin, FieldInstanceInterface $instance, array $form, array &$form_state) {
+  protected function alterSettingsForm(array &$settings_form, $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state) {
     $context = array(
       'formatter' => $plugin,
-      'field' => $instance->getField(),
-      'instance' => $instance,
+      'field_definition' => $field_definition,
       'view_mode' => $this->mode,
       'form' => $form,
     );
@@ -204,11 +203,10 @@ protected function alterSettingsForm(array &$settings_form, $plugin, FieldInstan
   /**
    * {@inheritdoc}
    */
-  protected function alterSettingsSummary(array &$summary, $plugin, FieldInstanceInterface $instance) {
+  protected function alterSettingsSummary(array &$summary, $plugin, FieldDefinitionInterface $field_definition) {
     $context = array(
       'formatter' => $plugin,
-      'field' => $instance->getField(),
-      'instance' => $instance,
+      'field_definition' => $field_definition,
       'view_mode' => $this->mode,
     );
     drupal_alter('field_formatter_settings_summary', $summary, $context);
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
index 3a9b442..81f3f48 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
@@ -10,8 +10,8 @@
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManager;
-use Drupal\field\FieldInstanceInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -20,6 +20,13 @@
 abstract class DisplayOverviewBase extends OverviewBase {
 
   /**
+   * The display context. Either 'view' or 'form'.
+   *
+   * @var string
+   */
+  protected $displayContext;
+
+  /**
    * The widget or formatter plugin manager.
    *
    * @var \Drupal\Component\Plugin\PluginManagerBase
@@ -79,6 +86,28 @@ public function getRegions() {
   }
 
   /**
+   * Collects the definitions of fields whose display is configurable.
+   *
+   * @return \Drupal\Core\Field\FieldDefinitionInterface[]
+   *   The array of field definitions
+   */
+  protected function getFieldDefinitions() {
+    // @todo Replace this entire implementation with
+    //   \Drupal::entityManager()->getFieldDefinition() when it can hand the
+    //   $instance objects - https://drupal.org/node/2114707
+    $entity = _field_create_entity_from_ids((object) array('entity_type' => $this->entity_type, 'bundle' => $this->bundle, 'entity_id' => NULL));
+    $field_definitions = array();
+    foreach ($entity as $field_name => $items) {
+      $field_definitions[$field_name] = $items->getFieldDefinition();
+    }
+
+    $context = $this->displayContext;
+    return array_filter($field_definitions, function(FieldDefinitionInterface $field_definition) use ($context) {
+      return $field_definition->isDisplayConfigurable($context);
+    });
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function buildForm(array $form, array &$form_state, $entity_type = NULL, $bundle = NULL) {
@@ -88,8 +117,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
       $this->mode = 'default';
     }
 
-    // Gather type information.
-    $instances = field_info_instances($this->entity_type, $this->bundle);
+    $field_definitions = $this->getFieldDefinitions();
     $extra_fields = $this->getExtraFields();
     $entity_display = $this->getEntityDisplay($this->mode);
 
@@ -101,11 +129,11 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
       '#entity_type' => $this->entity_type,
       '#bundle' => $this->bundle,
       '#mode' => $this->mode,
-      '#fields' => array_keys($instances),
+      '#fields' => array_keys($field_definitions),
       '#extra' => array_keys($extra_fields),
     );
 
-    if (empty($instances) && empty($extra_fields)) {
+    if (empty($field_definitions) && empty($extra_fields)) {
       drupal_set_message($this->t('There are no fields yet added. You can add new fields on the <a href="@link">Manage fields</a> page.', array('@link' => url($this->adminPath . '/fields'))), 'warning');
       return $form;
     }
@@ -140,8 +168,8 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
     );
 
     // Field rows.
-    foreach ($instances as $field_id => $instance) {
-      $table[$field_id] = $this->buildFieldRow($field_id, $instance, $entity_display, $form, $form_state);
+    foreach ($field_definitions as $field_name => $field_definition) {
+      $table[$field_name] = $this->buildFieldRow($field_definition, $entity_display, $form, $form_state);
     }
 
     // Non-field elements.
@@ -214,10 +242,8 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
   /**
    * Builds the table row structure for a single field.
    *
-   * @param string $field_id
-   *   The field ID.
-   * @param \Drupal\field\FieldInstanceInterface $instance
-   *   The field instance.
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The field definition.
    * @param \Drupal\Core\Entity\Display\EntityDisplayInterface $entity_display
    *   The entity display.
    * @param array $form
@@ -228,9 +254,10 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
    * @return array
    *   A table row array.
    */
-  protected function buildFieldRow($field_id, FieldInstanceInterface $instance, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
-    $display_options = $entity_display->getComponent($field_id);
-    $label = $instance->getLabel();
+  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
+    $field_name = $field_definition->getName();
+    $display_options = $entity_display->getComponent($field_name);
+    $label = $field_definition->getLabel();
 
     $field_row = array(
       '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
@@ -238,7 +265,7 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
       '#region_callback' => array($this, 'getRowRegion'),
       '#js_settings' => array(
         'rowHandler' => 'field',
-        'defaultPlugin' => $this->getDefaultPlugin($instance->getType()),
+        'defaultPlugin' => $this->getDefaultPlugin($field_definition->getType()),
       ),
       'human_name' => array(
         '#markup' => check_plain($label),
@@ -259,11 +286,11 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
           '#options' => drupal_map_assoc(array_keys($this->getRegions())),
           '#empty_value' => '',
           '#attributes' => array('class' => array('field-parent')),
-          '#parents' => array('fields', $field_id, 'parent'),
+          '#parents' => array('fields', $field_name, 'parent'),
         ),
         'hidden_name' => array(
           '#type' => 'hidden',
-          '#default_value' => $field_id,
+          '#default_value' => $field_name,
           '#attributes' => array('class' => array('field-name')),
         ),
       ),
@@ -275,9 +302,9 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
         '#type' => 'select',
         '#title' => $this->t('Plugin for @title', array('@title' => $label)),
         '#title_display' => 'invisible',
-        '#options' => $this->getPluginOptions($instance->getType()),
+        '#options' => $this->getPluginOptions($field_definition->getType()),
         '#default_value' => $display_options ? $display_options['type'] : 'hidden',
-        '#parents' => array('fields', $field_id, 'type'),
+        '#parents' => array('fields', $field_name, 'type'),
         '#attributes' => array('class' => array('field-plugin-type')),
       ),
       'settings_edit_form' => array(),
@@ -285,15 +312,15 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
 
     // Check the currently selected plugin, and merge persisted values for its
     // settings.
-    if (isset($form_state['values']['fields'][$field_id]['type'])) {
-      $display_options['type'] = $form_state['values']['fields'][$field_id]['type'];
+    if (isset($form_state['values']['fields'][$field_name]['type'])) {
+      $display_options['type'] = $form_state['values']['fields'][$field_name]['type'];
     }
-    if (isset($form_state['plugin_settings'][$field_id])) {
-      $display_options['settings'] = $form_state['plugin_settings'][$field_id];
+    if (isset($form_state['plugin_settings'][$field_name])) {
+      $display_options['settings'] = $form_state['plugin_settings'][$field_name];
     }
 
     // Get the corresponding plugin object.
-    $plugin = $this->getPlugin($instance, $display_options);
+    $plugin = $this->getPlugin($field_definition, $display_options);
 
     // Base button element for the various plugin settings actions.
     $base_button = array(
@@ -303,10 +330,10 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
         'wrapper' => 'field-display-overview-wrapper',
         'effect' => 'fade',
       ),
-      '#field_name' => $field_id,
+      '#field_name' => $field_name,
     );
 
-    if ($form_state['plugin_settings_edit'] == $field_id) {
+    if ($form_state['plugin_settings_edit'] == $field_name) {
       // We are currently editing this field's plugin settings. Display the
       // settings form and submit buttons.
       $field_row['plugin']['settings_edit_form'] = array();
@@ -314,14 +341,14 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
       if ($plugin) {
         // Generate the settings form and allow other modules to alter it.
         $settings_form = $plugin->settingsForm($form, $form_state);
-        $this->alterSettingsForm($settings_form, $plugin, $instance, $form, $form_state);
+        $this->alterSettingsForm($settings_form, $plugin, $field_definition, $form, $form_state);
 
         if ($settings_form) {
           $field_row['plugin']['#cell_attributes'] = array('colspan' => 3);
           $field_row['plugin']['settings_edit_form'] = array(
             '#type' => 'container',
             '#attributes' => array('class' => array('field-plugin-settings-edit-form')),
-            '#parents' => array('fields', $field_id, 'settings_edit_form'),
+            '#parents' => array('fields', $field_name, 'settings_edit_form'),
             'label' => array(
               '#markup' => $this->t('Plugin settings'),
             ),
@@ -330,18 +357,18 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
               '#type' => 'actions',
               'save_settings' => $base_button + array(
                 '#type' => 'submit',
-                '#name' => $field_id . '_plugin_settings_update',
+                '#name' => $field_name . '_plugin_settings_update',
                 '#value' => $this->t('Update'),
                 '#op' => 'update',
               ),
               'cancel_settings' => $base_button + array(
                 '#type' => 'submit',
-                '#name' => $field_id . '_plugin_settings_cancel',
+                '#name' => $field_name . '_plugin_settings_cancel',
                 '#value' => $this->t('Cancel'),
                 '#op' => 'cancel',
                 // Do not check errors for the 'Cancel' button, but make sure we
                 // get the value of the 'plugin type' select.
-                '#limit_validation_errors' => array(array('fields', $field_id, 'type')),
+                '#limit_validation_errors' => array(array('fields', $field_name, 'type')),
               ),
             ),
           );
@@ -359,7 +386,7 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
         $summary = $plugin->settingsSummary();
 
         // Allow other modules to alter the summary.
-        $this->alterSettingsSummary($summary, $plugin, $instance);
+        $this->alterSettingsSummary($summary, $plugin, $field_definition);
 
         if (!empty($summary)) {
           $field_row['settings_summary'] = array(
@@ -373,13 +400,13 @@ protected function buildFieldRow($field_id, FieldInstanceInterface $instance, En
         if ($plugin_definition['settings']) {
           $field_row['settings_edit'] = $base_button + array(
             '#type' => 'image_button',
-            '#name' => $field_id . '_settings_edit',
+            '#name' => $field_name . '_settings_edit',
             '#src' => 'core/misc/configure-dark.png',
             '#attributes' => array('class' => array('field-plugin-settings-edit'), 'alt' => $this->t('Edit')),
             '#op' => 'edit',
             // Do not check errors for the 'Edit' button, but make sure we get
             // the value of the 'plugin type' select.
-            '#limit_validation_errors' => array(array('fields', $field_id, 'type')),
+            '#limit_validation_errors' => array(array('fields', $field_name, 'type')),
             '#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
             '#suffix' => '</div>',
           );
@@ -646,12 +673,14 @@ public function multistepAjax($form, &$form_state) {
    * @return array
    *   An array of extra field info, as provided by field_info_extra_fields().
    */
-  abstract protected function getExtraFields();
+  protected function getExtraFields() {
+    return field_info_extra_fields($this->entity_type, $this->bundle, ($this->displayContext == 'view' ? 'display' : $this->displayContext));
+  }
 
   /**
    * Returns the widget or formatter plugin for a field.
    *
-   * @param \Drupal\field\FieldInstanceInterface $instance
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
    *   The field instance.
    * @param array $configuration
    *   The plugin configuration
@@ -659,7 +688,7 @@ public function multistepAjax($form, &$form_state) {
    * @return object
    *   The corresponding plugin.
    */
-  abstract protected function getPlugin($instance, $configuration);
+  abstract protected function getPlugin(FieldDefinitionInterface $field_definition, $configuration);
 
   /**
    * Returns an array of widget or formatter options for a field type.
@@ -808,14 +837,14 @@ protected function saveDisplayStatuses($display_statuses) {
    *   The widget or formatter settings form.
    * @param object $plugin
    *   The widget or formatter.
-   * @param FieldInstanceInterface $instance
-   *   The field instance.
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The field definition.
    * @param array $form
    *   The The (entire) configuration form array.
    * @param array $form_state
    *   The form state.
    */
-  abstract protected function alterSettingsForm(array &$settings_form, $plugin, FieldInstanceInterface $instance, array $form, array &$form_state);
+  abstract protected function alterSettingsForm(array &$settings_form, $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state);
 
   /**
    * Alters the widget or formatter settings summary.
@@ -824,9 +853,9 @@ protected function saveDisplayStatuses($display_statuses) {
    *   The widget or formatter settings summary.
    * @param object $plugin
    *   The widget or formatter.
-   * @param FieldInstanceInterface $instance
-   *   The field instance.
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The field definition.
    */
-  abstract protected function alterSettingsSummary(array &$summary, $plugin, FieldInstanceInterface $instance);
+  abstract protected function alterSettingsSummary(array &$summary, $plugin, FieldDefinitionInterface $field_definition);
 
 }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FormDisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FormDisplayOverview.php
index ec256c3..25794f6 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/FormDisplayOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FormDisplayOverview.php
@@ -7,9 +7,8 @@
 
 namespace Drupal\field_ui;
 
-use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
-use Drupal\field\FieldInstanceInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -20,6 +19,11 @@ class FormDisplayOverview extends DisplayOverviewBase {
   /**
    * {@inheritdoc}
    */
+  protected $displayContext = 'form';
+
+  /**
+   * {@inheritdoc}
+   */
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.manager'),
@@ -49,12 +53,14 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
   /**
    * {@inheritdoc}
    */
-  protected function buildFieldRow($field_id, FieldInstanceInterface $instance, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
-    $field_row = parent::buildFieldRow($field_id, $instance, $entity_display, $form, $form_state);
+  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
+    $field_row = parent::buildFieldRow($field_definition, $entity_display, $form, $form_state);
+
+    $field_name = $field_definition->getName();
 
     // Update the (invisible) title of the 'plugin' column.
-    $field_row['plugin']['#title'] = $this->t('Formatter for @title', array('@title' => $instance->getLabel()));
-    if (!empty($field_row['plugin']['settings_edit_form']) && ($plugin = $entity_display->getRenderer($field_id))) {
+    $field_row['plugin']['#title'] = $this->t('Formatter for @title', array('@title' => $field_definition->getLabel()));
+    if (!empty($field_row['plugin']['settings_edit_form']) && ($plugin = $entity_display->getRenderer($field_name))) {
       $plugin_type_info = $plugin->getPluginDefinition();
       $field_row['plugin']['settings_edit_form']['label']['#markup'] = $this->t('Widget settings:') . ' <span class="plugin-name">' . $plugin_type_info['label'] . '</span>';
     }
@@ -72,19 +78,12 @@ protected function getEntityDisplay($mode) {
   /**
    * {@inheritdoc}
    */
-  protected function getExtraFields() {
-    return field_info_extra_fields($this->entity_type, $this->bundle, 'form');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getPlugin($instance, $configuration) {
+  protected function getPlugin(FieldDefinitionInterface $field_definition, $configuration) {
     $plugin = NULL;
 
     if ($configuration && $configuration['type'] != 'hidden') {
       $plugin = $this->pluginManager->getInstance(array(
-        'field_definition' => $instance,
+        'field_definition' => $field_definition,
         'form_mode' => $this->mode,
         'configuration' => $configuration
       ));
@@ -143,11 +142,10 @@ protected function getOverviewPath($mode) {
   /**
    * {@inheritdoc}
    */
-  protected function alterSettingsForm(array &$settings_form, $plugin, FieldInstanceInterface $instance, array $form, array &$form_state) {
+  protected function alterSettingsForm(array &$settings_form, $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state) {
     $context = array(
       'widget' => $plugin,
-      'field' => $instance->getField(),
-      'instance' => $instance,
+      'field_definition' => $field_definition,
       'form_mode' => $this->mode,
       'form' => $form,
     );
@@ -157,11 +155,10 @@ protected function alterSettingsForm(array &$settings_form, $plugin, FieldInstan
   /**
    * {@inheritdoc}
    */
-  protected function alterSettingsSummary(array &$summary, $plugin, FieldInstanceInterface $instance) {
+  protected function alterSettingsSummary(array &$summary, $plugin, FieldDefinitionInterface $field_definition) {
     $context = array(
       'widget' => $plugin,
-      'field' => $instance->getField(),
-      'instance' => $instance,
+      'field_definition' => $field_definition,
       'form_mode' => $this->mode,
     );
     drupal_alter('field_widget_settings_summary', $summary, $context);
diff --git a/core/modules/forum/config/entity.display.taxonomy_term.forums.default.yml b/core/modules/forum/config/entity.display.taxonomy_term.forums.default.yml
index 647d655..ca4f340 100644
--- a/core/modules/forum/config/entity.display.taxonomy_term.forums.default.yml
+++ b/core/modules/forum/config/entity.display.taxonomy_term.forums.default.yml
@@ -7,4 +7,3 @@ status: true
 content:
   description:
     weight: 0
-    visible: true
diff --git a/core/modules/forum/config/entity.form_display.taxonomy_term.forums.default.yml b/core/modules/forum/config/entity.form_display.taxonomy_term.forums.default.yml
index 30b8929..b3d15bf 100644
--- a/core/modules/forum/config/entity.form_display.taxonomy_term.forums.default.yml
+++ b/core/modules/forum/config/entity.form_display.taxonomy_term.forums.default.yml
@@ -7,7 +7,5 @@ status: true
 content:
   name:
     weight: -5
-    visible: true
   description:
     weight: 0
-    visible: true
diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php
index fee4c18..c22dbed 100644
--- a/core/modules/node/lib/Drupal/node/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Entity/Node.php
@@ -373,6 +373,8 @@ public static function baseFieldDefinitions($entity_type) {
       ->setDescription(t('The node language code.'));
 
     $fields['title'] = FieldDefinition::create('text')
+      // @todo Account for $node_type->title_label when per-bundle overrides are
+      //   possible - https://drupal.org/node/2114707.
       ->setLabel(t('Title'))
       ->setDescription(t('The title of this node, always treated as non-markup plain text.'))
       ->setClass('\Drupal\node\NodeTitleItemList')
@@ -382,7 +384,17 @@ public static function baseFieldDefinitions($entity_type) {
         'default_value' => '',
         'max_length' => 255,
         'text_processing' => 0,
-      ));
+      ))
+      ->setDisplayOptions('view', array(
+        'label' => 'hidden',
+        'type' => 'text_default',
+        'weight' => -5,
+      ))
+      ->setDisplayOptions('form', array(
+        'type' => 'text_textfield',
+        'weight' => -5,
+      ))
+      ->setDisplayConfigurable('form', TRUE);
 
     $fields['uid'] = FieldDefinition::create('entity_reference')
       ->setLabel(t('User ID'))
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 9a9f154..48b2176 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -203,12 +203,6 @@ function node_entity_display_alter(EntityViewDisplayInterface $display, $context
         }
       }
     }
-    // @todo Manage base field displays in the YAML:
-    //   https://drupal.org/node/2144919.
-    $display->setComponent('title', array(
-      'label' => 'hidden',
-      'type' => 'text_default',
-    ));
   }
 }
 
@@ -217,16 +211,8 @@ function node_entity_display_alter(EntityViewDisplayInterface $display, $context
  */
 function node_entity_form_display_alter(EntityFormDisplayInterface $form_display, $context) {
   if ($context['entity_type'] == 'node') {
-    // @todo Manage base field displays in the YAML:
-    //   https://drupal.org/node/2144919.
     $node_type = node_type_load($context['bundle']);
-    if ($node_type->has_title) {
-      // Title is also registered in node_field_extra_fields().
-      $options = $form_display->getComponent('title') ?: array('weight' => -5);
-      $options['type'] = 'text_textfield';
-      $form_display->setComponent('title', $options);
-    }
-    else {
+    if (!$node_type->has_title) {
       $form_display->removeComponent('title');
     }
   }
@@ -477,16 +463,8 @@ function node_field_extra_fields() {
   $description = t('Node module element');
 
   foreach (node_type_get_types() as $bundle) {
-    if ($bundle->has_title) {
-      $extra['node'][$bundle->type]['form']['title'] = array(
-        'label' => check_plain($bundle->title_label),
-        'description' => $description,
-        'weight' => -5,
-      );
-    }
-
-    // Add also the 'language' select if Language module is enabled and the
-    // bundle has multilingual support.
+    // Add the 'language' select if Language module is enabled and the bundle
+    // has multilingual support.
     // Visibility of the ordering of the language selector is the same as on the
     // node/add form.
     if ($module_language_enabled) {
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
index 79b65b5..01cb381 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
@@ -212,7 +212,7 @@ function testEnableModulesFixedList() {
     $this->assertTrue(TRUE == $entity_manager->getDefinition('entity_test'));
 
     // Install some other modules; entity_test should still exist.
-    $this->container->get('module_handler')->install(array('field', 'field_test'), FALSE);
+    $this->container->get('module_handler')->install(array('user', 'field', 'field_test'), FALSE);
     $this->assertEqual($this->container->get('module_handler')->moduleExists('entity_test'), TRUE);
     $this->assertTrue(TRUE == $entity_manager->getDefinition('entity_test'));
 
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 4547ea7..ee69cbb 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -198,7 +198,7 @@ function entity_test_entity_form_mode_info_alter(&$form_modes) {
  * Implements hook_field_extra_fields().
  */
 function entity_test_field_extra_fields() {
-  $extra['entity_test']['entity_test'] = array(
+  $extra['entity_test']['bundle_with_extra_fields'] = array(
     'display' => array(
       // Note: those extra fields do not currently display anything, they are
       // just used in \Drupal\entity\Tests\EntityDisplayTest to test the
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php
new file mode 100644
index 0000000..8134acf
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestBaseFieldDisplay.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\Entity\EntityTestBaseFieldDisplay.
+ */
+
+namespace Drupal\entity_test\Entity;
+
+use Drupal\Core\Field\FieldDefinition;
+
+/**
+ * Defines a test entity class for base fields display.
+ *
+ * @EntityType(
+ *   id = "entity_test_base_field_display",
+ *   label = @Translation("Test entity - base field display"),
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Entity\FieldableDatabaseStorageController",
+ *     "access" = "Drupal\entity_test\EntityTestAccessController",
+ *     "form" = {
+ *       "default" = "Drupal\entity_test\EntityTestFormController"
+ *     },
+ *     "translation" = "Drupal\content_translation\ContentTranslationController"
+ *   },
+ *   base_table = "entity_test",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "uuid" = "uuid",
+ *     "revision" = "revision_id",
+ *     "bundle" = "type"
+ *   },
+ *   links = {
+ *     "edit-form" = "entity_test.edit_entity_test",
+ *     "admin-form" = "entity_test.admin_entity_test"
+ *   }
+ * )
+ */
+class EntityTestBaseFieldDisplay extends EntityTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions($entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+
+    $fields['test_no_display'] = FieldDefinition::create('text')
+      ->setLabel(t('Field with no display'));
+
+    $fields['test_display_configurable'] = FieldDefinition::create('text')
+      ->setLabel(t('Field with configurable display'))
+      ->setDisplayOptions('view', array(
+        'type' => 'text_default',
+        'weight' => 10,
+      ))
+      ->setDisplayConfigurable('view', TRUE)
+      ->setDisplayOptions('form', array(
+        'type' => 'text_textfield',
+        'weight' => 10,
+      ))
+      ->setDisplayConfigurable('form', TRUE);
+
+    $fields['test_display_non_configurable'] = FieldDefinition::create('text')
+      ->setLabel(t('Field with non-configurable display'))
+      ->setDisplayOptions('view', array(
+        'type' => 'text_default',
+        'weight' => 11,
+      ))
+      ->setDisplayOptions('form', array(
+        'type' => 'text_textfield',
+        'weight' => 11,
+      ));
+
+    return $fields;
+  }
+
+}
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index a194b00..137165f 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -684,9 +684,7 @@ function user_update_8011() {
       'weight' => 0,
     ))
     ->set('status', 1)
-    ->set('content.member_for', array(
-      'visible' => FALSE,
-    ));
+    ->set('hidden.member_for', TRUE);
   $display->save();
 
   // Add file usage for the default field.
diff --git a/core/profiles/standard/config/entity.display.user.user.compact.yml b/core/profiles/standard/config/entity.display.user.user.compact.yml
index d83a3dd..85b7992 100644
--- a/core/profiles/standard/config/entity.display.user.user.compact.yml
+++ b/core/profiles/standard/config/entity.display.user.user.compact.yml
@@ -11,6 +11,6 @@ content:
       image_style: thumbnail
       image_link: content
     weight: 0
-  member_for:
-    visible: false
+hidden:
+  member_for: true
 status: true
