diff --git a/includes/common.inc b/includes/common.inc
index e2fa6dea37aca6a7a98ba7de52f98010c5ef9472..ed635e6c07cd588b30bdf6f8e5231af4f6efcd61 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -6386,6 +6386,11 @@ function entity_get_info($entity_type = NULL) {
           'revision' => '',
           'bundle' => '',
         );
+        foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) {
+          $entity_info[$name]['view modes'][$view_mode] += array(
+            'custom settings' => FALSE,
+          );
+        }
         // If no bundle key is provided, assume a single bundle, named after
         // the entity type.
         if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) {
diff --git a/modules/blog/blog.module b/modules/blog/blog.module
index f1c30ebceaa1dde53176e0a5dcca7d83bedc5afa..5e09d50dbe3736bfacb02a5c416db9f37c2f807f 100644
--- a/modules/blog/blog.module
+++ b/modules/blog/blog.module
@@ -77,7 +77,7 @@ function blog_view($node, $view_mode) {
 /**
  * Implements hook_node_view().
  */
-function blog_node_view($node, $view_mode = 'full') {
+function blog_node_view($node, $view_mode) {
   if ($view_mode != 'rss') {
     if ($node->type == 'blog' && (arg(0) != 'blog' || arg(1) != $node->uid)) {
       $links['blog_usernames_blog'] = array(
diff --git a/modules/book/book.module b/modules/book/book.module
index ddf8455638fd21a1c43ad872151ec0410e337f7b..bea4a077faac9758441bfe4cc279e1bab48e26a4 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -240,6 +240,7 @@ function book_entity_info_alter(&$info) {
   $info['node']['view modes'] += array(
     'print' => array(
       'label' => t('Print'),
+      'custom settings' => FALSE,
     ),
   );
 }
diff --git a/modules/comment/comment.install b/modules/comment/comment.install
index 9523926649c7cf0c25927214177499754fb7fb3f..b7a249044efcdc25c0dd2f5ef911e410f371353b 100644
--- a/modules/comment/comment.install
+++ b/modules/comment/comment.install
@@ -279,10 +279,12 @@ function comment_update_7012() {
     'label' => 'Comment',
     'entity_type' => 'comment',
     'settings' => array('text_processing' => 1),
-    // Hide field label by default.
+    'required' => TRUE,
     'display' => array(
-      'full' => array(
+      'default' => array(
         'label' => 'hidden',
+        'type' => 'text_default',
+        'weight' => 0,
       ),
     ),
   );
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 945c7e0bc2830c64db96527719c783bb71805f4a..66ccef6bc1185f38b7d4b7a897ff6e491ef8ceb0 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -108,6 +108,7 @@ function comment_entity_info() {
       'view modes' => array(
         'full' => array(
           'label' => t('Full comment'),
+          'custom settings' => FALSE,
         ),
       ),
       'static cache' => FALSE,
@@ -165,15 +166,17 @@ function comment_field_extra_fields() {
   foreach (node_type_get_types() as $type) {
     if (variable_get('comment_subject_field_' . $type->type, 1) == 1) {
       $return['comment']['comment_node_' . $type->type] = array(
-        'author' => array(
-          'label' => t('Author'),
-          'description' => t('Author textfield'),
-          'weight' => -2,
-        ),
-        'title' => array(
-          'label' => t('Subject'),
-          'description' => t('Subject textfield'),
-          'weight' => -1,
+        'form' => array(
+          'author' => array(
+            'label' => t('Author'),
+            'description' => t('Author textfield'),
+            'weight' => -2,
+          ),
+          'title' => array(
+            'label' => t('Subject'),
+            'description' => t('Subject textfield'),
+            'weight' => -1,
+          ),
         ),
       );
     }
@@ -362,10 +365,11 @@ function _comment_body_field_instance_create($info) {
     'bundle' => 'comment_node_' . $info->type,
     'settings' => array('text_processing' => 1),
     'required' => TRUE,
-    // Hides field label by default.
     'display' => array(
-      'full' => array(
+      'default' => array(
         'label' => 'hidden',
+        'type' => 'text_default',
+        'weight' => 0,
       ),
     ),
   );
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index bc4e266905c15ac6255610f2a937e9246daea7e3..f43322c75426fe3b416e95496d6abc5fb17a1104 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -7,55 +7,59 @@
  */
 
 /**
- * Expose "pseudo-field" components on fieldable entities.
+ * Exposes "pseudo-field" components on fieldable entities.
  *
- * Field UI's 'Manage fields' page lets users re-order fields, but also
- * non-field components. For nodes, these include the title, menu settings, and
- * other elements exposed by contributed modules through hook_form() and
+ * Field UI's "Manage fields" and "Manage display" pages let users re-order
+ * fields, but also non-field components. For nodes, these include the title,
+ * poll choices, and other elements exposed by modules through hook_form() or
  * hook_form_alter().
  *
- * Fieldable entities or contributed modules that want to have their components
- * supported should expose them using this hook, and use
- * field_attach_extra_weight() to retrieve the user-defined weight when
- * inserting the component.
+ * Fieldable entities or modules that want to have their components supported
+ * should expose them using this hook. The user-defined settings (weight,
+ * visibility) are automatically applied on rendered forms and displayed
+ * entities in a #pre_render callback added by field_attach_form() and
+ * field_attach_view().
+ *
+ * @see _field_extra_fields_pre_render()
+ * @see hook_field_extra_fields_alter()
  *
  * @return
- *   A nested array of 'pseudo-field' components. Each list is nested within the
- *   field bundle to which those components apply. The keys are the name of the
- *   element as it appears in the form structure. The values are arrays with the
- *   following key/value pairs:
+ *   A nested array of 'pseudo-field' components. Each list is nested within
+ *   the following keys: entity type, bundle name, context (either 'form' or
+ *   'display'). The keys are the name of the elements as appearing in the
+ *   renderable array (either the entity form or the displayed entity). The
+ *   value is an associative array:
  *   - label: The human readable name of the component.
  *   - description: A short description of the component contents.
  *   - weight: The default weight of the element.
- *   - view: (optional) The name of the element as it appears in the rendered
- *     structure, if different from the name in the form.
- *
- * @see hook_field_extra_fields_alter()
  */
 function hook_field_extra_fields() {
-  $extra = array();
-
-  foreach (node_type_get_types() as $bundle) {
-    if ($type->has_title) {
-      $extra['node'][$bundle]['title'] = array(
-        'label' => $type->title_label,
-        'description' => t('Node module element.'),
-        'weight' => -5,
-      );
-    }
-  }
-  if (module_exists('poll')) {
-    $extra['node']['poll']['choice_wrapper'] = array(
-      'label' => t('Poll choices'),
-      'description' => t('Poll module choices.'),
-      'weight' => -4,
-    );
-    $extra['node']['poll']['settings'] = array(
-      'label' => t('Poll settings'),
-      'description' => t('Poll module settings.'),
-      'weight' => -3,
-    );
-  }
+  $extra['node']['poll'] = array(
+    'form' => array(
+      'choice_wrapper' => array(
+        'label' => t('Poll choices'),
+        'description' => t('Poll choices'),
+        'weight' => -4,
+      ),
+      'settings' => array(
+        'label' => t('Poll settings'),
+        'description' => t('Poll module settings'),
+        'weight' => -3,
+      ),
+    ),
+    'display' => array(
+      'poll_view_voting' => array(
+        'label' => t('Poll vote'),
+        'description' => t('Poll vote'),
+        'weight' => 0,
+      ),
+      'poll_view_results' => array(
+        'label' => t('Poll results'),
+        'description' => t('Poll results'),
+        'weight' => 0,
+      ),
+    )
+  );
 
   return $extra;
 }
@@ -1651,6 +1655,91 @@ function hook_field_storage_pre_query($field_name, $conditions, $options, &$skip
   // @todo Needs function body.
 }
 
+/**
+ * Alters the display settings of a field before it gets displayed.
+ *
+ * Note that instead of hook_field_display_alter(), which is called for all
+ * fields on all entity types, hook_field_display_ENTITY_TYPE_alter() may be
+ * used to alter display settings for fields on a specific entity type only.
+ *
+ * This hook is called once per field per displayed entity. If the result of the
+ * hook involves reading from the database, it is highly recommended to
+ * statically cache the information.
+ *
+ * @param $display
+ *   The display settings that will be used to display the field values, as
+ *   found in the 'display' key of $instance definitions.
+ * @param $context
+ *   An associative array containing:
+ *   - entity_type: The entity type; e.g. 'node' or 'user'.
+ *   - field: The field being rendered.
+ *   - instance: The instance being rendered.
+ *   - view_mode: The view mode, e.g. 'full', 'teaser'...
+ *
+ * @see hook_field_display_ENTITY_TYPE_alter()
+ */
+function hook_field_display_alter(&$display, $context) {
+  // Leave field labels out of the search index.
+  // Note: The check against $context['entity_type'] == 'node' could be avoided
+  // by using hook_field_display_node_alter() instead of
+  // hook_field_display_alter(), resulting in less function calls when
+  // rendering non-node entities.
+  if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') {
+    $display['label'] = 'hidden';
+  }
+}
+
+/**
+ * Alters the display settings of a field on a given entity type before it gets displayed.
+ *
+ * Modules can implement hook_field_display_ENTITY_TYPE_alter() to alter display
+ * settings for fields on a specific entity type, rather than implementing
+ * hook_field_display_alter().
+ *
+ * This hook is called once per field per displayed entity. If the result of the
+ * hook involves reading from the database, it is highly recommended to
+ * statically cache the information.
+ *
+ * @param $display
+ *   The display settings that will be used to display the field values, as
+ *   found in the 'display' key of $instance definitions.
+ * @param $context
+ *   An associative array containing:
+ *   - entity_type: The entity type; e.g. 'node' or 'user'.
+ *   - field: The field being rendered.
+ *   - instance: The instance being rendered.
+ *   - view_mode: The view mode, e.g. 'full', 'teaser'...
+ *
+ * @see hook_field_display_alter()
+ */
+function hook_field_display_ENTITY_TYPE_alter(&$display, $context) {
+  // Leave field labels out of the search index.
+  if ($context['view_mode'] == 'search_index') {
+    $display['label'] = 'hidden';
+  }
+}
+
+/**
+ * Alters the display settings of pseudo-fields before an entity is displayed.
+ *
+ * This hook is called once per displayed entity. If the result of the hook
+ * involves reading from the database, it is highly recommended to statically
+ * cache the information.
+ *
+ * @param $displays
+ *   An array of display settings for the pseudo-fields in the entity, keyed
+ *   by pseudo-field names.
+ * @param $context
+ *   An associative array containing:
+ *   - entity_type: The entity type; e.g. 'node' or 'user'.
+ *   - bundle: The bundle name.
+ *   - view_mode: The view mode, e.g. 'full', 'teaser'...
+ */
+function hook_field_extra_fields_display_alter(&$displays, $context) {
+  if ($context['entity_type'] == 'taxonomy_term' && $context['view_mode'] == 'full') {
+    $displays['description']['visibility'] = FALSE;
+  }
+}
 /**
  * @} End of "ingroup field_storage"
  */
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index 3896e213492521c52fbea9ddf0747abee3c32606..8a7991d41f07d45c8a5daa1eb6139a89fd068479 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -552,8 +552,9 @@ function field_attach_form($entity_type, $entity, &$form, &$form_state, $langcod
   // Add custom weight handling.
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
   $form['#attached']['css'][] = drupal_get_path('module', 'field') . '/theme/field.css';
-  $form['#pre_render'][] = '_field_extra_weights_pre_render';
-  $form['#extra_fields'] = field_extra_fields($entity_type, $bundle);
+  $form['#pre_render'][] = '_field_extra_fields_pre_render';
+  $form['#entity_type'] = $entity_type;
+  $form['#bundle'] = $bundle;
 
   // Save the original entity to allow later re-use.
   $form_state['entity'] = $entity;
@@ -1185,7 +1186,7 @@ function field_attach_query_revisions($field_id, $conditions, $options = array()
  * @param $view_mode
  *   View mode, e.g. 'full', 'teaser'...
  */
-function field_attach_prepare_view($entity_type, $entities, $view_mode = 'full') {
+function field_attach_prepare_view($entity_type, $entities, $view_mode) {
   // To ensure hooks are only run once per entity, only process items without
   // the _field_view_prepared flag.
   // @todo: resolve this more generally for both entity and field level hooks.
@@ -1250,7 +1251,7 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode = 'full')
  * @return
  *   A renderable array for the field values.
  */
-function field_attach_view($entity_type, $entity, $view_mode = 'full', $langcode = NULL) {
+function field_attach_view($entity_type, $entity, $view_mode, $langcode = NULL) {
   // Determine the actual language to display for each field, given the
   // languages available in the field data.
   $display_language = field_language($entity_type, $entity, NULL, $langcode);
@@ -1262,8 +1263,9 @@ function field_attach_view($entity_type, $entity, $view_mode = 'full', $langcode
 
   // Add custom weight handling.
   list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
-  $output['#pre_render'][] = '_field_extra_weights_pre_render';
-  $output['#extra_fields'] = field_extra_fields($entity_type, $bundle);
+  $output['#pre_render'][] = '_field_extra_fields_pre_render';
+  $output['#entity_type'] = $entity_type;
+  $output['#bundle'] = $bundle;
 
   // Include CSS styles.
   $output['#attached']['css'][] = drupal_get_path('module', 'field') . '/theme/field.css';
@@ -1381,6 +1383,14 @@ function field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
   // Clear the cache.
   field_cache_clear();
 
+  // Update bundle settings.
+  $settings = variable_get('field_bundle_settings', array());
+  if (isset($settings[$entity_type][$bundle_old])) {
+    $settings[$entity_type][$bundle_new] = $settings[$entity_type][$bundle_old];
+    unset($settings[$entity_type][$bundle_old]);
+    variable_set('field_bundle_settings', $settings);
+  }
+
   // Let other modules act on renaming the bundle.
   module_invoke_all('field_attach_rename_bundle', $entity_type, $bundle_old, $bundle_new);
 }
@@ -1410,6 +1420,13 @@ function field_attach_delete_bundle($entity_type, $bundle) {
   // Clear the cache.
   field_cache_clear();
 
+  // Clear bundle display settings.
+  $settings = variable_get('field_bundle_settings', array());
+  if (isset($settings[$entity_type][$bundle])) {
+    unset($settings[$entity_type][$bundle]);
+    variable_set('field_bundle_settings', $settings);
+  }
+
   // Let other modules act on deleting the bundle.
   module_invoke_all('field_attach_delete_bundle', $entity_type, $bundle, $instances);
 }
diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc
index 904e69d2607653c021f43ea59f216a234496952b..4f58cd445b265ded615ea67c6e97ba639e43a9d0 100644
--- a/modules/field/field.crud.inc
+++ b/modules/field/field.crud.inc
@@ -31,8 +31,7 @@
  * field_attach_load() then loads the 'subtitle' and 'photo' fields
  * because they are both attached to the 'node' bundle 'article'.
  *
- * Field definitions are (currently) represented as an array of key/value
- * pairs. The array properties are:
+ * Field definitions are represented as an array of key/value pairs.
  *
  * @param array $field:
  * - id (integer, read-only)
@@ -96,8 +95,7 @@
  *         A sub-array of key/value pairs of settings. Each storage backend
  *         defines and documents its own settings.
  *
- * Field Instance definitions are (currently) represented as an array of
- * key/value pairs. The array properties are:
+ * Field instance definitions are represented as an array of key/value pairs.
  *
  * @param array $instance:
  * - id (integer, read-only)
@@ -154,11 +152,20 @@
  *     - module (string, read-only)
  *         The name of the module that implements the widget type.
  * - display (array)
- *     A sub-array of key/value pairs identifying view modes and the way the
- *     field values should be displayed in each mode.
- *     - full (array)
- *         A sub-array of key/value pairs of the display options to be used
- *         when the field is being displayed in the "full" view mode.
+ *     A sub-array of key/value pairs identifying the way field values should
+ *     be displayed in each of the entity type's view modes, plus the 'default'
+ *     mode. For each view mode, Field UI lets site administrators define
+ *     whether they want to use a dedicated set of display options or the
+ *     'default' options to reduce the number of displays to maintain as they
+ *     add new fields. For nodes, on a fresh install, only the 'teaser' view
+ *     mode is configured to use custom display options, all other view modes
+ *     defined use the 'default' options by default. When programmatically
+ *     adding field instances on nodes, it is therefore recommended to at least
+ *     specify display options for 'default' and 'teaser'.
+ *     - default (array)
+ *         A sub-array of key/value pairs describing the display options to be
+ *         used when the field is being displayed in view modes that are not
+ *         configured to use dedicated display options.
  *         - label (string)
  *             Position of the label. 'inline', 'above' and 'hidden' are the
  *             values recognized by the default 'field' theme implementation.
@@ -172,7 +179,11 @@
  *            displayed in this view mode.
  *         - module (string, read-only)
  *             The name of the module which implements the display formatter.
- *     - teaser
+ *     - some_mode
+ *         A sub-array of key/value pairs describing the display options to be
+ *         used when the field is being displayed in the 'some_mode' view mode.
+ *         Those options will only be actually applied at run time if the view
+ *         mode is not configured to use default settings for this bundle.
  *         - ...
  *     - other_mode
  *        - ...
@@ -607,12 +618,16 @@ function field_delete_field($field_name) {
  *     - settings: each omitted setting is given the default value specified in
  *       hook_field_widget_info().
  *   - display:
- *     Settings for the 'full' view mode will be added, and each view mode
- *     will be completed with the following default values:
+ *     Settings for the 'default' view mode will be added if not present, and
+ *     each view mode in the definition will be completed with the following
+ *     default values:
  *     - label: 'above'
  *     - type: the default formatter specified in hook_field_info().
  *     - settings: each omitted setting is given the default value specified in
  *       hook_field_formatter_info().
+ *     View modes not present in the definition are left empty, and the field
+ *     will not be displayed in this mode.
+ *
  * @return
  *   The $instance array with the id property filled in.
  * @throw
@@ -730,7 +745,6 @@ function _field_write_instance($instance, $update = FALSE) {
     'required' => FALSE,
     'label' => $instance['field_name'],
     'description' => '',
-    'weight' => 0,
     'deleted' => 0,
   );
 
@@ -742,30 +756,55 @@ function _field_write_instance($instance, $update = FALSE) {
     // TODO: what if no 'default_widget' specified ?
     'type' => $field_type['default_widget'],
     'settings' => array(),
-    'weight' => 0,
   );
+  // If no weight specified, make sure the field sinks at the bottom.
+  if (!isset($instance['widget']['weight'])) {
+    $weights = array();
+    foreach (field_info_instances($instance['entity_type'], $instance['bundle']) as $existing_instance) {
+      if ($instance['field_name'] != $existing_instance['field_name']) {
+        $weights[] = $existing_instance['widget']['weight'];
+      }
+    }
+    foreach (field_extra_fields($instance['entity_type'], $instance['bundle'], 'form') as $extra) {
+      $weights[] = $extra['weight'];
+    }
+    $instance['widget']['weight'] = $weights ? max($weights) + 1 : 0;
+  }
   // Check widget module.
   $widget_type = field_info_widget_types($instance['widget']['type']);
   $instance['widget']['module'] = $widget_type['module'];
   $instance['widget']['settings'] += field_info_widget_settings($instance['widget']['type']);
 
-  // Make sure there is at least display info for the 'full' view mode.
+  // Make sure there are at least display settings for the 'default' view mode,
+  // and fill in defaults for each view mode specified in the definition.
   $instance['display'] += array(
-    'full' => array(),
+    'default' => array(),
   );
-  // Set default display settings for each view mode.
   foreach ($instance['display'] as $view_mode => $display) {
-    $instance['display'][$view_mode] += array(
+    $display += array(
       'label' => 'above',
-      // TODO: what if no 'default_formatter' specified ?
-      'type' => $field_type['default_formatter'],
+      'type' => isset($field_type['default_formatter']) ? $field_type['default_formatter'] : 'hidden',
       'settings' => array(),
-      'weight' => 0,
     );
-    $formatter_type = field_info_formatter_types($instance['display'][$view_mode]['type']);
-    // TODO : 'hidden' will raise PHP warnings.
-    $instance['display'][$view_mode]['module'] = $formatter_type['module'];
-    $instance['display'][$view_mode]['settings'] += field_info_formatter_settings($instance['display'][$view_mode]['type']);
+    if ($display['type'] != 'hidden') {
+      $formatter_type = field_info_formatter_types($display['type']);
+      $display['module'] = $formatter_type['module'];
+      $display['settings'] += field_info_formatter_settings($display['type']);
+    }
+    // If no weight specified, make sure the field sinks at the bottom.
+    if (!isset($display['weight'])) {
+      $weights = array();
+      foreach (field_info_instances($instance['entity_type'], $instance['bundle']) as $existing_instance) {
+        if ($instance['field_name'] != $existing_instance['field_name']) {
+          $weights[] = $existing_instance['display'][$view_mode]['weight'];
+        }
+      }
+      foreach (field_extra_fields($instance['entity_type'], $instance['bundle'], 'display') as $extra) {
+        $weights[] = $extra['display'][$view_mode]['weight'];
+      }
+      $display['weight'] = $weights ? max($weights) + 1 : 0;
+    }
+    $instance['display'][$view_mode] = $display;
   }
 
   // The serialized 'data' column contains everything from $instance that does
diff --git a/modules/field/field.default.inc b/modules/field/field.default.inc
index 62ab6178e0bf67be614a1ca493d785d0979303ed..eebde1e14f56ea2c4ad34cb26c42310dc7595580 100644
--- a/modules/field/field.default.inc
+++ b/modules/field/field.default.inc
@@ -132,7 +132,10 @@ function field_default_prepare_view($entity_type, $entities, $field, $instances,
   // Group entities, instances and items by formatter module.
   $modules = array();
   foreach ($instances as $id => $instance) {
-    $display = is_string($display) ? $instance['display'][$display] : $display;
+    if (is_string($display)) {
+      $view_mode = $display;
+      $display = field_get_display($instance, $view_mode);
+    }
     if ($display['type'] !== 'hidden') {
       $module = $display['module'];
       $modules[$module] = $module;
@@ -183,18 +186,13 @@ function field_default_view($entity_type, $entity, $field, $instance, $langcode,
   // Prepare incoming display specifications.
   if (is_string($display)) {
     $view_mode = $display;
-    $display = $instance['display'][$view_mode];
+    $display = field_get_display($instance, $view_mode);
   }
   else {
     $view_mode = '_custom_display';
   }
 
   if ($display['type'] !== 'hidden') {
-    // We never want to index fields labels.
-    if ($view_mode == 'search_index') {
-      $display['label'] = 'hidden';
-    }
-
     // Calling the formatter function through module_invoke() can have a
     // performance impact on pages with many fields and values.
     $function = $display['module'] . '_field_formatter_view';
diff --git a/modules/field/field.info.inc b/modules/field/field.info.inc
index a4517684c4b052fb51cdb953b87054672f7ded5a..ff5cd4e0ed06a57ec8f81efdf19afc21326bf7ad 100644
--- a/modules/field/field.info.inc
+++ b/modules/field/field.info.inc
@@ -290,11 +290,16 @@ function _field_info_prepare_instance($instance, $field) {
     $instance['display'][$view_mode] = _field_info_prepare_instance_display($field, $display);
   }
 
-  // Fallback to 'full' display settings for unspecified view modes.
+  // Fallback to 'hidden' for unspecified view modes.
   $entity_info = entity_get_info($instance['entity_type']);
   foreach ($entity_info['view modes'] as $view_mode => $info) {
     if (!isset($instance['display'][$view_mode])) {
-      $instance['display'][$view_mode] = $instance['display']['full'];
+      $instance['display'][$view_mode] = array(
+        'type' => 'hidden',
+        'label' => 'above',
+        'settings' => array(),
+        'weight' => 0,
+      );
     }
   }
 
diff --git a/modules/field/field.module b/modules/field/field.module
index d470c9fd71d79228a5c5e5038b3a380d198ef72f..4182e88a1b02ec9dd2735405390c29be3a9aa655 100644
--- a/modules/field/field.module
+++ b/modules/field/field.module
@@ -365,75 +365,308 @@ function _field_sort_items_value_helper($a, $b) {
 }
 
 /**
- * Registry of pseudo-field components in a given bundle.
+ * Gets or sets administratively defined bundle settings.
+ *
+ * For each bundle, settings are provided as a nested array with the following
+ * structure:
+ * @code
+ * array(
+ *   'view_modes' => array(
+ *     // One sub-array per view mode for the entity type:
+ *     'full' => array(
+ *       'custom_display' => Whether the view mode uses custom display
+ *         settings or settings of the 'default' mode,
+ *     ),
+ *     'teaser' => ...
+ *   ),
+ *   'extra_fields' => array(
+ *     'form' => array(
+ *       // One sub-array per pseudo-field in displayed entities:
+ *       'extra_field_1' => array(
+ *         'weight' => The weight of the pseudo-field,
+ *       ),
+ *       'extra_field_2' => ...
+ *     ),
+ *     'display' => array(
+ *       // One sub-array per pseudo-field in displayed entities:
+ *       'extra_field_1' => array(
+ *         // One sub-array per view mode for the entity type, including
+ *         // the 'default' mode:
+ *         'default' => array(
+ *           'weight' => The weight of the pseudo-field,
+ *           'visibility' => Whether the pseudo-field is visible or hidden,
+ *         ),
+ *         'full' => ...
+ *       ),
+ *       'extra_field_2' => ...
+ *     ),
+ *   ),
+ * ),
+ * @encode
  *
  * @param $entity_type
  *   The type of $entity; e.g. 'node' or 'user'.
  * @param $bundle
  *   The bundle name.
+ * @param $settings
+ *   (optional) The settings to store.
+ *
+ * @return
+ *   If no $settings are passed, the current settings are returned.
+ */
+function field_bundle_settings($entity_type, $bundle, $settings = NULL) {
+  $stored_settings = variable_get('field_bundle_settings', array());
+
+  if (isset($settings)) {
+    $stored_settings[$entity_type][$bundle] = $settings;
+    variable_set('field_bundle_settings', $stored_settings);
+    drupal_static_reset('field_view_mode_settings');
+    drupal_static_reset('field_extra_fields');
+  }
+  else {
+    $settings = isset($stored_settings[$entity_type][$bundle]) ? $stored_settings[$entity_type][$bundle] : array();
+    $settings += array(
+      'view_modes' => array(),
+      'extra_fields' => array(),
+    );
+
+    return $settings;
+  }
+}
+
+/**
+ * Returns view mode settings in a given bundle.
+ *
+ * @param $entity_type
+ *   The type of entity; e.g. 'node' or 'user'.
+ * @param $bundle
+ *   The bundle name to return view mode settings for.
+ *
+ * @return
+ *   An array keyed by view mode, with the following key/value pairs:
+ *   - custom_settings: Boolean specifying whether the view mode uses a
+ *     dedicated set of display options (TRUE), or the 'default' options
+ *     (FALSE). Defaults to FALSE.
+ */
+function field_view_mode_settings($entity_type, $bundle) {
+  $cache = &drupal_static(__FUNCTION__, array());
+
+  if (!isset($cache[$entity_type][$bundle])) {
+    $bundle_settings = field_bundle_settings($entity_type, $bundle);
+    $settings = $bundle_settings['view_modes'];
+    // Include view modes for which nothing has been stored yet, but whose
+    // definition in hook_entity_info() specify they should use custom settings
+    // by default.
+    $entity_info = entity_get_info($entity_type);
+    foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
+      if (!isset($settings[$view_mode]['custom_settings']) && $view_mode_info['custom settings']) {
+        $settings[$view_mode]['custom_settings'] = TRUE;
+      }
+    }
+    $cache[$entity_type][$bundle] = $settings;
+  }
+
+  return $cache[$entity_type][$bundle];
+}
+
+/**
+ * Returns a list and settings of pseudo-field elements in a given bundle.
+ *
+ * If $context is 'form', an array with the following structure:
+ * @code
+ *   array(
+ *     'name_of_pseudo_field_component' => array(
+ *       'label' => The human readable name of the component,
+ *       'description' => A short description of the component content,
+ *       'weight' => The weight of the component in edit forms,
+ *     ),
+ *     'name_of_other_pseudo_field_component' => array(
+ *       // ...
+ *     ),
+ *   );
+ * @endcode
+ *
+ * If $context is 'display', an array with the following structure:
+ * @code
+ *   array(
+ *     'name_of_pseudo_field_component' => array(
+ *       'label' => The human readable name of the component,
+ *       'description' => A short description of the component content,
+ *       // One entry per view mode, including the 'default' mode:
+ *       'display' => array(
+ *         'default' => array(
+ *           'weight' => The weight of the component in displayed entities in
+ *             this view mode,
+ *           'visibility' => Whether the component is visible or hidden in
+ *             displayed entities in this view mode,
+ *         ),
+ *         'teaser' => array(
+ *           // ...
+ *         ),
+ *       ),
+ *     ),
+ *     'name_of_other_pseudo_field_component' => array(
+ *       // ...
+ *     ),
+ *   );
+ * @endcode
+ *
+ * @param $entity_type
+ *   The type of entity; e.g. 'node' or 'user'.
+ * @param $bundle
+ *   The bundle name.
+ * @param $context
+ *   The context for which the list of pseudo-fields is requested. Either
+ *   'form' or 'display'.
+ *
  * @return
  *   The array of pseudo-field elements in the bundle.
  */
-function field_extra_fields($entity_type, $bundle) {
-  $info = &drupal_static(__FUNCTION__, array());
+function field_extra_fields($entity_type, $bundle, $context) {
+  $extra = &drupal_static(__FUNCTION__);
 
-  if (empty($info)) {
+  if (!isset($extra)) {
     $info = (array) module_invoke_all('field_extra_fields');
     drupal_alter('field_extra_fields', $info);
 
-    // Add saved weights. The array is keyed by entity type, bundle and
-    // element name.
-    $extra_weights = variable_get('field_extra_weights', array());
-    foreach ($extra_weights as $entity_type_name => $bundles) {
-      foreach ($bundles as $bundle_name => $weights) {
-        foreach ($weights as $key => $value) {
-          if (isset($info[$entity_type_name][$bundle_name][$key])) {
-            $info[$entity_type_name][$bundle_name][$key]['weight'] = $value;
+    // Merge in saved settings, and make sure we have settings for all view
+    // modes.
+    foreach ($info as $entity_type_name => $bundles) {
+      $entity_type_info = entity_get_info($entity_type_name);
+      foreach ($bundles as $bundle_name => $extra_fields) {
+        $bundle_settings = field_bundle_settings($entity_type_name, $bundle_name);
+        $extra_fields += array('form' => array(), 'display' => array());
+
+        // Extra fields in forms.
+        $data = $extra_fields['form'];
+        foreach ($data as $name => $field_data) {
+          $settings = isset($bundle_settings['extra_fields']['form'][$name]) ? $bundle_settings['extra_fields']['form'][$name] : array();
+          if (isset($settings['weight'])) {
+            $data[$name]['weight'] = $settings['weight'];
           }
         }
+        $extra[$entity_type_name][$bundle_name]['form'] = $data;
+
+        // Extra fields in displayed entities.
+        $data = $extra_fields['display'];
+        foreach ($data as $name => $field_data) {
+          $settings = isset($bundle_settings['extra_fields']['display'][$name]) ? $bundle_settings['extra_fields']['display'][$name] : array();
+          $view_modes = array_merge(array('default'), array_keys($entity_type_info['view modes']));
+          foreach ($view_modes as $view_mode) {
+            if (isset($settings[$view_mode])) {
+              $data[$name]['display'][$view_mode] = $settings[$view_mode];
+            }
+            else {
+              $data[$name]['display'][$view_mode] = array(
+                'weight' => $field_data['weight'],
+                'visible' => TRUE,
+              );
+            }
+            unset($data[$name]['weight']);
+          }
+        }
+        $extra[$entity_type_name][$bundle_name]['display'] = $data;
       }
     }
   }
 
-  return isset($info[$entity_type][$bundle]) ? $info[$entity_type][$bundle]: array();
+  return isset($extra[$entity_type][$bundle][$context]) ? $extra[$entity_type][$bundle][$context] : array();
+}
+
+
+/**
+ * Returns the display settings to use for an instance in a given view mode.
+ *
+ * @param $instance
+ *   The field instance being displayed.
+ * @param $view_mode
+ *   The view mode.
+ *
+ * @return
+ *   The display settings to be used when displaying the field values.
+ */
+function field_get_display($instance, $view_mode) {
+  // Check whether the view mode uses custom display settings or the 'default'
+  // mode.
+  $view_mode_settings = field_view_mode_settings($instance['entity_type'], $instance['bundle']);
+  $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default');
+  $display = $instance['display'][$actual_mode];
+
+  // Let modules alter the display settings.
+  $context = array(
+    'entity_type' => $instance['entity_type'],
+    'field' => field_info_field($instance['field_name']),
+    'instance' => $instance,
+    'view_mode' => $view_mode,
+  );
+  drupal_alter(array('field_display', 'field_display_' . $instance['entity_type']), $display, $context);
+
+  return $display;
 }
 
 /**
- * Retrieve the user-defined weight for a 'pseudo-field' component.
+ * Returns the display settings to use for pseudo-fields in a given view mode.
  *
  * @param $entity_type
  *   The type of $entity; e.g. 'node' or 'user'.
  * @param $bundle
  *   The bundle name.
- * @param $pseudo_field
- *   The name of the 'pseudo-field'.
+ * @param $view_mode
+ *   The view mode.
+ *
  * @return
- *   The weight for the 'pseudo-field', respecting the user settings stored by
- *   field.module.
+ *   The display settings to be used when viewing the bundle's pseudo-fields.
  */
-function field_extra_field_weight($entity_type, $bundle, $pseudo_field) {
-  $extra = field_extra_fields($entity_type, $bundle);
-  if (isset($extra[$pseudo_field])) {
-    return $extra[$pseudo_field]['weight'];
+function field_extra_fields_get_display($entity_type, $bundle, $view_mode) {
+  // Check whether the view mode uses custom display settings or the 'default'
+  // mode.
+  $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
+  $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings'])) ? $view_mode : 'default';
+  $extra_fields = field_extra_fields($entity_type, $bundle, 'display');
+
+  $displays = array();
+  foreach ($extra_fields as $name => $value) {
+    $displays[$name] = $extra_fields[$name]['display'][$actual_mode];
   }
+
+  // Let modules alter the display settings.
+  $context = array(
+    'entity_type' => $entity_type,
+    'bundle' => $bundle,
+    'view_mode' => $view_mode,
+  );
+  drupal_alter('field_extra_fields_display', $displays, $context);
+
+  return $displays;
 }
 
 /**
- * Pre-render callback to adjust weights of non-field elements on entities.
+ * Pre-render callback to adjust weights and visibility of non-field elements.
  */
-function _field_extra_weights_pre_render($elements) {
-  if (isset($elements['#extra_fields'])) {
-    foreach ($elements['#extra_fields'] as $key => $value) {
-      // Some core 'fields' use a different key in node forms and in 'view'
-      // render arrays. Ensure that we are not on a form first.
-      if (!isset($elements['#build_id']) && isset($value['view']) && isset($elements[$value['view']])) {
-        $elements[$value['view']]['#weight'] = $value['weight'];
+function _field_extra_fields_pre_render($elements) {
+  $entity_type = $elements['#entity_type'];
+  $bundle = $elements['#bundle'];
+
+  if (isset($elements['#type']) && $elements['#type'] == 'form') {
+    $extra_fields = field_extra_fields($entity_type, $bundle, 'form');
+    foreach ($extra_fields as $name => $settings) {
+      if (isset($elements[$name])) {
+        $elements[$name]['#weight'] = $settings['weight'];
       }
-      elseif (isset($elements[$key])) {
-        $elements[$key]['#weight'] = $value['weight'];
+    }
+  }
+  elseif (isset($elements['#view_mode'])) {
+    $view_mode = $elements['#view_mode'];
+    $extra_fields = field_extra_fields_get_display($entity_type, $bundle, $view_mode);
+    foreach ($extra_fields as $name => $settings) {
+      if (isset($elements[$name])) {
+        $elements[$name]['#weight'] = $settings['weight'];
+        // Visibility: make sure we do not accidentally show a hidden element.
+        $elements[$name]['#access'] = isset($elements[$name]['#access']) ? ($elements[$name]['#access'] && $settings['visible']) : $settings['visible'];
       }
     }
   }
+
   return $elements;
 }
 
@@ -543,7 +776,7 @@ function field_view_value($entity_type, $entity, $field_name, $item, $display =
  *     display settings specified for this view mode in the $instance
  *     definition for the field in the entity's bundle.
  *     If no display settings are found for the view mode, the settings for
- *     the 'full' view mode will be used.
+ *     the 'default' view mode will be used.
  *   - An array of display settings, as found in the 'display' entry of
  *     $instance definitions. The following key/value pairs are allowed:
  *     - label: (string) Position of the label. The default 'field' theme
@@ -574,15 +807,6 @@ function field_view_field($entity_type, $entity, $field_name, $display = array()
       // When using custom display settings, fill in default values.
       $display = _field_info_prepare_instance_display($field, $display);
     }
-    else {
-      // When using a view mode, make sure we have settings for it, or fall
-      // back to the 'full' view mode.
-      list(, , $bundle) = entity_extract_ids($entity_type, $entity);
-      $instance = field_info_instance($entity_type, $field_name, $bundle);
-      if (!isset($instance['display'][$display])) {
-        $display = 'full';
-      }
-    }
 
     // Hook invocations are done through the _field_invoke() functions in
     // 'single field' mode, to reuse the language fallback logic.
diff --git a/modules/field/modules/text/text.test b/modules/field/modules/text/text.test
index cbd135f74b13c0e627e9cc1b7d26f44b52224ff8..52f757e636ab1f2a25673360b4f4d443a85ba19a 100644
--- a/modules/field/modules/text/text.test
+++ b/modules/field/modules/text/text.test
@@ -46,7 +46,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
         'type' => 'text_textfield',
       ),
       'display' => array(
-        'full' => array(
+        'default' => array(
           'type' => 'text_default',
         ),
       ),
@@ -94,7 +94,12 @@ class TextFieldTestCase extends DrupalWebTestCase {
       ),
       'widget' => array(
         'type' => $widget_type,
-      )
+      ),
+      'display' => array(
+        'full' => array(
+          'type' => 'text_default',
+        ),
+      ),
     );
     field_create_instance($this->instance);
     $langcode = LANGUAGE_NONE;
@@ -116,7 +121,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
 
     // Display the entity.
     $entity = field_test_entity_test_load($id);
-    $entity->content = field_attach_view($entity_type, $entity);
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $this->content = drupal_render($entity->content);
     $this->assertText($value, 'Filtered tags are not displayed');
   }
@@ -148,7 +153,12 @@ class TextFieldTestCase extends DrupalWebTestCase {
       ),
       'widget' => array(
         'type' => $widget_type,
-      )
+      ),
+      'display' => array(
+        'full' => array(
+          'type' => 'text_default',
+        ),
+      ),
     );
     field_create_instance($this->instance);
     $langcode = LANGUAGE_NONE;
@@ -180,7 +190,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
 
     // Display the entity.
     $entity = field_test_entity_test_load($id);
-    $entity->content = field_attach_view($entity_type, $entity);
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $this->content = drupal_render($entity->content);
     $this->assertNoRaw($value, t('HTML tags are not displayed.'));
     $this->assertRaw(check_plain($value), t('Escaped HTML is displayed correctly.'));
@@ -213,7 +223,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
 
     // Display the entity.
     $entity = field_test_entity_test_load($id);
-    $entity->content = field_attach_view($entity_type, $entity);
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $this->content = drupal_render($entity->content);
     $this->assertRaw($value, t('Value is displayed unfiltered'));
   }
diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test
index 632e474caf19470c289671894a7044123bda2cff..fa24ada88f7100fff49c244fb6a4dae635871940 100644
--- a/modules/field/tests/field.test
+++ b/modules/field/tests/field.test
@@ -871,8 +871,8 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
       ),
     );
     field_update_instance($this->instance);
-    field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
-    $entity->content = field_attach_view($entity_type, $entity);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $output = drupal_render($entity->content);
     $this->content = $output;
     $this->assertRaw($this->instance['label'], "Label is displayed.");
@@ -885,8 +885,8 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
     $entity = clone($entity_init);
     $this->instance['display']['full']['label'] = 'hidden';
     field_update_instance($this->instance);
-    field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
-    $entity->content = field_attach_view($entity_type, $entity);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $output = drupal_render($entity->content);
     $this->content = $output;
     $this->assertNoRaw($this->instance['label'], "Hidden label: label is not displayed.");
@@ -900,8 +900,8 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
       ),
     );
     field_update_instance($this->instance);
-    field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
-    $entity->content = field_attach_view($entity_type, $entity);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $output = drupal_render($entity->content);
     $this->content = $output;
     $this->assertNoRaw($this->instance['label'], "Hidden field: label is not displayed.");
@@ -922,8 +922,8 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
       ),
     );
     field_update_instance($this->instance);
-    field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
-    $entity->content = field_attach_view($entity_type, $entity);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $output = drupal_render($entity->content);
     $display = $formatter_setting;
     foreach ($values as $delta => $value) {
@@ -945,8 +945,8 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
       ),
     );
     field_update_instance($this->instance);
-    field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
-    $entity->content = field_attach_view($entity_type, $entity);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $output = drupal_render($entity->content);
     $this->content = $output;
     foreach ($values as $delta => $value) {
@@ -1332,8 +1332,8 @@ class FieldInfoTestCase extends FieldTestCase {
     $data['settings'] = array();
     $data['widget']['settings'] = 'unavailable_widget';
     $data['widget']['settings'] = array();
-    $data['display']['full']['type'] = 'unavailable_formatter';
-    $data['display']['full']['settings'] = array();
+    $data['display']['default']['type'] = 'unavailable_formatter';
+    $data['display']['default']['settings'] = array();
     db_update('field_config_instance')
       ->fields(array('data' => serialize($data)))
       ->condition('field_name', $instance_definition['field_name'])
@@ -1354,13 +1354,11 @@ class FieldInfoTestCase extends FieldTestCase {
     $widget_type = field_info_widget_types($instance['widget']['type']);
     $this->assertIdentical($instance['widget']['settings'], $widget_type['settings'] , t('All expected widget settings are present.'));
 
-    // Check that the default formatter is used and expected settings are in place.
-    $entity_info = entity_get_info('test_entity');
-    foreach ($entity_info['view modes'] as $view_mode => $info) {
-      $this->assertIdentical($instance['display'][$view_mode]['type'], $field_type['default_formatter'], t('Unavailable formatter replaced with default formatter in view_mode %view_mode', array('%view_mode' => $view_mode)));
-      $formatter_type = field_info_formatter_types($instance['display'][$view_mode]['type']);
-      $this->assertIdentical($instance['display'][$view_mode]['settings'], $formatter_type['settings'] , t('All expected formatter settings are present in view_mode %view_mode', array('%view_mode' => $view_mode)));
-    }
+    // Check that display settings are set for the 'default' mode.
+    $display = $instance['display']['default'];
+    $this->assertIdentical($display['type'], $field_type['default_formatter'], t("Formatter is set for the 'default' view mode"));
+    $formatter_type = field_info_formatter_types($display['type']);
+    $this->assertIdentical($display['settings'], $formatter_type['settings'] , t("Formatter settings are set for the 'default' view mode"));
   }
 
   /**
@@ -1792,7 +1790,13 @@ class FieldDisplayAPITestCase extends FieldTestCase {
       'bundle' => 'test_bundle',
       'label' => $this->label,
       'display' => array(
-        'full' => array(
+        'default' => array(
+          'type' => 'field_test_default',
+          'settings' => array(
+            'test_formatter_setting' => $this->randomName(),
+          ),
+        ),
+        'teaser' => array(
           'type' => 'field_test_default',
           'settings' => array(
             'test_formatter_setting' => $this->randomName(),
@@ -1862,19 +1866,19 @@ class FieldDisplayAPITestCase extends FieldTestCase {
 
     // View mode: check that display settings specified in the instance are
     // used.
-    $output = field_view_field('test_entity', $this->entity, $this->field_name, 'full');
+    $output = field_view_field('test_entity', $this->entity, $this->field_name, 'teaser');
     $this->drupalSetContent(drupal_render($output));
-    $setting = $this->instance['display']['full']['settings']['test_formatter_setting'];
+    $setting = $this->instance['display']['teaser']['settings']['test_formatter_setting'];
     $this->assertText($this->label, t('Label was displayed.'));
     foreach($this->values as $delta => $value) {
       $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
 
-    // Unknown view mode: check that display settings for 'full' view mode
+    // Unknown view mode: check that display settings for 'default' view mode
     // are used.
     $output = field_view_field('test_entity', $this->entity, $this->field_name, 'unknown_view_mode');
     $this->drupalSetContent(drupal_render($output));
-    $setting = $this->instance['display']['full']['settings']['test_formatter_setting'];
+    $setting = $this->instance['display']['default']['settings']['test_formatter_setting'];
     $this->assertText($this->label, t('Label was displayed.'));
     foreach($this->values as $delta => $value) {
       $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
@@ -1929,17 +1933,17 @@ class FieldDisplayAPITestCase extends FieldTestCase {
 
     // View mode: check that display settings specified in the instance are
     // used.
-    $setting = $this->instance['display']['full']['settings']['test_formatter_setting'];
+    $setting = $this->instance['display']['teaser']['settings']['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
       $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
-      $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'full');
+      $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'teaser');
       $this->drupalSetContent(drupal_render($output));
       $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
     }
 
-    // Unknown view mode: check that display settings for 'full' view mode
+    // Unknown view mode: check that display settings for 'default' view mode
     // are used.
-    $setting = $this->instance['display']['full']['settings']['test_formatter_setting'];
+    $setting = $this->instance['display']['default']['settings']['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
       $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
       $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'unknown_view_mode');
@@ -2446,13 +2450,13 @@ class FieldInstanceCrudTestCase extends FieldTestCase {
     $this->assertIdentical($record['data']['label'], $this->instance_definition['field_name'], t('Label defaults to field name.'));
     $this->assertIdentical($record['data']['description'], '', t('Description defaults to empty string.'));
     $this->assertIdentical($record['data']['widget']['type'], $field_type['default_widget'], t('Default widget has been written.'));
-    $this->assertTrue(isset($record['data']['display']['full']), t('Display for "full" view_mode has been written.'));
-    $this->assertIdentical($record['data']['display']['full']['type'], $field_type['default_formatter'], t('Default formatter for "full" view_mode has been written.'));
+    $this->assertTrue(isset($record['data']['display']['default']), t('Display for "full" view_mode has been written.'));
+    $this->assertIdentical($record['data']['display']['default']['type'], $field_type['default_formatter'], t('Default formatter for "full" view_mode has been written.'));
 
     // Check that default settings are set.
     $this->assertIdentical($record['data']['settings'], $field_type['instance_settings'] , t('Default instance settings have been written.'));
     $this->assertIdentical($record['data']['widget']['settings'], $widget_type['settings'] , t('Default widget settings have been written.'));
-    $this->assertIdentical($record['data']['display']['full']['settings'], $formatter_type['settings'], t('Default formatter settings for "full" view_mode have been written.'));
+    $this->assertIdentical($record['data']['display']['default']['settings'], $formatter_type['settings'], t('Default formatter settings for "full" view_mode have been written.'));
 
     // Guarantee that the field/bundle combination is unique.
     try {
@@ -2535,8 +2539,8 @@ class FieldInstanceCrudTestCase extends FieldTestCase {
     $instance['settings']['test_instance_setting'] = $this->randomName();
     $instance['widget']['settings']['test_widget_setting'] =$this->randomName();
     $instance['widget']['weight']++;
-    $instance['display']['full']['settings']['test_formatter_setting'] = $this->randomName();
-    $instance['display']['full']['weight']++;
+    $instance['display']['default']['settings']['test_formatter_setting'] = $this->randomName();
+    $instance['display']['default']['weight']++;
     field_update_instance($instance);
 
     $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
@@ -2545,23 +2549,23 @@ class FieldInstanceCrudTestCase extends FieldTestCase {
     $this->assertEqual($instance['description'], $instance_new['description'], t('"description" change is saved'));
     $this->assertEqual($instance['widget']['settings']['test_widget_setting'], $instance_new['widget']['settings']['test_widget_setting'], t('Widget setting change is saved'));
     $this->assertEqual($instance['widget']['weight'], $instance_new['widget']['weight'], t('Widget weight change is saved'));
-    $this->assertEqual($instance['display']['full']['settings']['test_formatter_setting'], $instance_new['display']['full']['settings']['test_formatter_setting'], t('Formatter setting change is saved'));
-    $this->assertEqual($instance['display']['full']['weight'], $instance_new['display']['full']['weight'], t('Widget weight change is saved'));
+    $this->assertEqual($instance['display']['default']['settings']['test_formatter_setting'], $instance_new['display']['default']['settings']['test_formatter_setting'], t('Formatter setting change is saved'));
+    $this->assertEqual($instance['display']['default']['weight'], $instance_new['display']['default']['weight'], t('Widget weight change is saved'));
 
     // Check that changing widget and formatter types updates the default settings.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $instance['widget']['type'] = 'test_field_widget_multiple';
-    $instance['display']['full']['type'] = 'field_test_multiple';
+    $instance['display']['default']['type'] = 'field_test_multiple';
     field_update_instance($instance);
 
     $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertEqual($instance['widget']['type'], $instance_new['widget']['type'] , t('Widget type change is saved.'));
     $settings = field_info_widget_settings($instance_new['widget']['type']);
     $this->assertIdentical($settings, array_intersect_key($instance_new['widget']['settings'], $settings) , t('Widget type change updates default settings.'));
-    $this->assertEqual($instance['display']['full']['type'], $instance_new['display']['full']['type'] , t('Formatter type change is saved.'));
-    $info = field_info_formatter_types($instance_new['display']['full']['type']);
+    $this->assertEqual($instance['display']['default']['type'], $instance_new['display']['default']['type'] , t('Formatter type change is saved.'));
+    $info = field_info_formatter_types($instance_new['display']['default']['type']);
     $settings = $info['settings'];
-    $this->assertIdentical($settings, array_intersect_key($instance_new['display']['full']['settings'], $settings) , t('Changing formatter type updates default settings.'));
+    $this->assertIdentical($settings, array_intersect_key($instance_new['display']['default']['settings'], $settings) , t('Changing formatter type updates default settings.'));
 
     // Check that adding a new view mode is saved and gets default settings.
     $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
diff --git a/modules/field/tests/field_test.entity.inc b/modules/field/tests/field_test.entity.inc
index cdd3b0c34696e3189b65dd6c7131e438d0682865..6bf582731ac8e2d99c7d983ad5a486515093cccb 100644
--- a/modules/field/tests/field_test.entity.inc
+++ b/modules/field/tests/field_test.entity.inc
@@ -14,9 +14,11 @@ function field_test_entity_info() {
   $test_entity_modes = array(
     'full' => array(
       'label' => t('Full object'),
+      'custom settings' => TRUE,
     ),
     'teaser' => array(
       'label' => t('Teaser'),
+      'custom settings' => TRUE,
     ),
   );
 
diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc
index 6be92ee591dab1ddb548c069fe8470c5f7b5aa11..2ede719627e6471ed0734f5b782acb75d19b1a49 100644
--- a/modules/field_ui/field_ui.admin.inc
+++ b/modules/field_ui/field_ui.admin.inc
@@ -83,7 +83,7 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
   $field_types = field_info_field_types();
   $widget_types = field_info_widget_types();
 
-  $extra = field_extra_fields($entity_type, $bundle);
+  $extra_fields = field_extra_fields($entity_type, $bundle, 'form');
 
   // Store each default weight so that we can add the 'add new' rows after them.
   $weights = array();
@@ -93,7 +93,7 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
     '#entity_type' => $entity_type,
     '#bundle' => $bundle,
     '#fields' => array_keys($instances),
-    '#extra' => array_keys($extra),
+    '#extra' => array_keys($extra_fields),
     '#field_rows' => array(),
   );
 
@@ -155,17 +155,17 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
   }
 
   // Non-field elements.
-  foreach ($extra as $name => $label) {
-    $weight = $extra[$name]['weight'];
+  foreach ($extra_fields as $name => $extra_field) {
+    $weight = $extra_field['weight'];
     $form[$name] = array(
       'label' => array(
-        '#markup' => t($extra[$name]['label']),
+        '#markup' => check_plain($extra_field['label']),
       ),
       'name' => array(
         '#markup' => $name,
       ),
       'description' => array(
-        '#markup' => isset($extra[$name]['description']) ? $extra[$name]['description'] : '',
+        '#markup' => isset($extra_field['description']) ? $extra_field['description'] : '',
       ),
       'weight' => array(
         '#type' => 'textfield',
@@ -173,10 +173,10 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
         '#size' => 3,
       ),
       'edit' => array(
-        '#markup' => isset($extra[$name]['edit']) ? $extra[$name]['edit'] : '',
+        '#markup' => isset($extra_field['edit']) ? $extra_field['edit'] : '',
       ),
       'delete' => array(
-        '#markup' => isset($extra[$name]['delete']) ? $extra[$name]['delete'] : '',
+        '#markup' => isset($extra_field['delete']) ? $extra_field['delete'] : '',
       ),
       'hidden_name' => array(
         '#type' => 'hidden',
@@ -464,8 +464,9 @@ function field_ui_field_overview_form_submit($form, &$form_state) {
   $bundle = $form['#bundle'];
   $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
 
+  $bundle_settings = field_bundle_settings($entity_type, $bundle);
+
   // Update field weights.
-  $extra = array();
   foreach ($form_values as $key => $values) {
     if (in_array($key, $form['#fields'])) {
       $instance = field_read_instance($entity_type, $key, $bundle);
@@ -476,13 +477,11 @@ function field_ui_field_overview_form_submit($form, &$form_state) {
       field_update_instance($instance);
     }
     elseif (in_array($key, $form['#extra'])) {
-      $extra[$key] = $values['weight'];
+      $bundle_settings['extra_fields']['form'][$key]['weight'] = $values['weight'];
     }
   }
 
-  $extra_weights = variable_get('field_extra_weights', array());
-  $extra_weights[$entity_type][$bundle] = $extra;
-  variable_set('field_extra_weights', $extra_weights);
+  field_bundle_settings($entity_type, $bundle, $bundle_settings);
 
   $destinations = array();
 
@@ -563,12 +562,9 @@ function field_ui_field_overview_form_submit($form, &$form_state) {
 }
 
 /**
- * Menu callback; presents a listing of fields display settings for a bundle.
- *
- * This form includes form widgets to select which fields appear in teaser and
- * full view modes, and how the field labels should be rendered.
+ * Menu callback; presents field display settings for a given view mode.
  */
-function field_ui_display_overview_form($form, &$form_state, $entity_type, $bundle, $view_modes_selector = 'basic') {
+function field_ui_display_overview_form($form, &$form_state, $entity_type, $bundle, $view_mode) {
   $bundle = field_extract_bundle($entity_type, $bundle);
 
   field_ui_inactive_message($entity_type, $bundle);
@@ -577,14 +573,14 @@ function field_ui_display_overview_form($form, &$form_state, $entity_type, $bund
   // Gather type information.
   $instances = field_info_instances($entity_type, $bundle);
   $field_types = field_info_field_types();
-  $view_modes = field_ui_view_modes_tabs($entity_type, $view_modes_selector);
+  $extra_fields = field_extra_fields($entity_type, $bundle, 'display');
 
   $form += array(
-    '#tree' => TRUE,
     '#entity_type' => $entity_type,
     '#bundle' => $bundle,
+    '#view_mode' => $view_mode,
     '#fields' => array_keys($instances),
-    '#contexts' => $view_modes_selector,
+    '#extra' => array_keys($extra_fields),
   );
 
   if (empty($instances)) {
@@ -592,85 +588,165 @@ function field_ui_display_overview_form($form, &$form_state, $entity_type, $bund
     return $form;
   }
 
-  // Fields.
-  $label_options = array(
+  $table = array(
+    '#theme' => 'field_ui_display_overview_table',
+    '#field_rows' => array(),
+    '#tree' => TRUE,
+  );
+
+  $field_label_options = array(
     'above' => t('Above'),
     'inline' => t('Inline'),
     'hidden' => t('<Hidden>'),
   );
+  $extra_visibility_options = array(
+    'visible' => t('Visible'),
+    'hidden' => t('Hidden'),
+  );
+
   foreach ($instances as $name => $instance) {
-    $field = field_info_field($instance['field_name']);
-    $weight = $instance['widget']['weight'];
+    $display = $instance['display'][$view_mode];
 
-    $form[$name] = array(
-      'human_name' => array('#markup' => check_plain($instance['label'])),
-      'weight' => array('#type' => 'value', '#value' => $weight),
+    $table[$name]['human_name'] = array(
+      '#markup' => check_plain($instance['label']),
     );
-    $defaults = $instance['display'];
+    $table[$name]['weight'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $display['weight'],
+      '#size' => 3,
+    );
+    $table[$name]['hidden_name'] = array(
+      '#type' => 'hidden',
+      '#default_value' => $name,
+    );
+    $table[$name]['label'] = array(
+      '#type' => 'select',
+      '#options' => $field_label_options,
+      '#default_value' => $display['label'],
+    );
+    $field = field_info_field($instance['field_name']);
 
     $formatter_options = field_ui_formatter_options($field['type']);
     $formatter_options['hidden'] = t('<Hidden>');
-    foreach ($view_modes as $view_mode) {
-      $display = isset($instance['display'][$view_mode]) ? $instance['display'][$view_mode] : $instance['display']['full'];
-      $form[$name][$view_mode]['label'] = array(
-        '#type' => 'select',
-        '#options' => $label_options,
-        '#default_value' => $display['label'],
-      );
-      $form[$name][$view_mode]['type'] = array(
-        '#type' => 'select',
-        '#options' => $formatter_options,
-        '#default_value' => $display['type'],
-      );
+    $table[$name]['type'] = array(
+      '#type' => 'select',
+      '#options' => $formatter_options,
+      '#default_value' => $display['type'],
+    );
+    $table['#field_rows'][] = $name;
+
+    // Collect default formatters for the JS script.
+    $field_type_info = field_info_field_types($field['type']);
+    $default_formatters[$name] = $field_type_info['default_formatter'];
+  }
+
+  // Non-field elements.
+  foreach ($extra_fields as $name => $extra_field) {
+    $display = $extra_field['display'][$view_mode];
+    $table[$name]['human_name'] = array(
+      '#markup' => check_plain($extra_field['label']),
+    );
+    $table[$name]['weight'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $display['weight'],
+      '#size' => 3,
+    );
+    $table[$name]['hidden_name'] = array(
+      '#type' => 'hidden',
+      '#default_value' => $name,
+    );
+    $table[$name]['type'] = array(
+      '#type' => 'select',
+      '#options' => $extra_visibility_options,
+      '#default_value' => $display['visible'] ? 'visible' : 'hidden',
+    );
+    $table['#field_rows'][] = $name;
+  }
+  $form['settings'] = $table;
+
+  // Custom display settings.
+  if ($view_mode == 'default') {
+    $form['modes'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Custom display settings'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    // Collect options and default values for the 'Custom display settings'
+    // checkboxes.
+    $options = array();
+    $default = array();
+    $entity_info = entity_get_info($entity_type);
+    $view_modes = $entity_info['view modes'];
+    $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
+    foreach ($view_modes as $view_mode_name => $view_mode_info) {
+      $options[$view_mode_name] = $view_mode_info['label'];
+      if (!empty($view_mode_settings[$view_mode_name]['custom_settings'])) {
+        $default[] = $view_mode_name;
+      }
     }
+    $form['modes']['view_modes_custom'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Use custom display settings for the following contexts'),
+      '#options' => $options,
+      '#default_value' => $default,
+    );
   }
 
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
+
+  $form['#attached']['js'][] = drupal_get_path('module', 'field_ui') . '/field_ui.js';
+  $form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.css';
+  drupal_add_js(array('fieldDefaultFormatters' => $default_formatters), 'setting');
+
   return $form;
 }
 
 /**
- * Theme preprocess function for field_ui-display-overview-form.tpl.php.
+ * Theme preprocess function for field_ui-display-overview-table.tpl.php.
  */
-function template_preprocess_field_ui_display_overview_form(&$vars) {
-  $form = &$vars['form'];
+function template_preprocess_field_ui_display_overview_table(&$vars) {
+  $elements = &$vars['elements'];
 
-  $contexts_selector = $form['#contexts'];
-  $view_modes = field_ui_view_modes_tabs($form['#entity_type'], $contexts_selector);
-  $entity_info = entity_get_info($form['#entity_type']);
-  $view_modes_info = $entity_info['view modes'];
-  $vars['contexts'] = array();
-  foreach ($view_modes as $view_mode) {
-    $vars['contexts'][$view_mode] = $view_modes_info[$view_mode]['label'];
-  }
+  $rows = array(
+    'visible' => array(),
+    'hidden' => array(),
+  );
 
-  $order = _field_ui_overview_order($form, $form['#fields']);
-  if (empty($order)) {
-    $vars['rows'] = array();
-    $vars['submit'] = '';
-    return;
-  }
-  $rows = array();
-  foreach ($order as $key) {
-    $element = &$form[$key];
-    $row = new stdClass();
-    foreach (element_children($element) as $child) {
-      if (array_key_exists('label', $element[$child])) {
-        $row->{$child} = new stdClass();
-        $row->{$child}->label = drupal_render($element[$child]['label']);
-        $row->{$child}->type = drupal_render($element[$child]['type']);
-      }
-      else {
-        $row->{$child} = drupal_render($element[$child]);
+  if (!empty($elements['#field_rows'])) {
+    drupal_add_tabledrag('field-display-overview', 'order', 'sibling', 'field-weight');
+
+    $order = _field_ui_overview_order($elements, $elements['#field_rows']);
+    foreach ($order as $key) {
+      $element = &$elements[$key];
+      $visibility = $element['type']['#value'] == 'hidden' ? 'hidden' : 'visible';
+
+      // Add target classes for the tabledrag behavior.
+      $element['weight']['#attributes']['class'][] = 'field-weight';
+      $element['hidden_name']['#attributes']['class'][] = 'field-name';
+      $element['type']['#attributes']['class'][] = 'field-formatter-type';
+      $element['type']['#attributes']['class'][] = "field-display-$visibility";
+      $element['type']['#attributes']['class'][] = "field-name-$key";
+
+      $row = new stdClass();
+      foreach (element_children($element) as $child) {
+        if (array_key_exists('label', $element[$child])) {
+          $row->{$child} = new stdClass();
+          $row->{$child}->label = drupal_render($element[$child]['label']);
+          $row->{$child}->type = drupal_render($element[$child]['type']);
+        }
+        else {
+          $row->{$child} = drupal_render($element[$child]);
+        }
       }
+      $row->class = 'draggable';
+      $row->label_class = 'label-field';
+      $rows[$visibility][] = $row;
     }
-    $row->label_class = 'label-field';
-    $rows[] = $row;
   }
 
   $vars['rows'] = $rows;
-  $vars['submit'] = drupal_render_children($form);
 }
 
 /**
@@ -678,17 +754,46 @@ function template_preprocess_field_ui_display_overview_form(&$vars) {
  */
 function field_ui_display_overview_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
-  foreach ($form_values as $key => $values) {
-    if (in_array($key, $form['#fields'])) {
-      $instance = field_info_instance($form['#entity_type'], $key, $form['#bundle']);
-      foreach ($instance['display'] as $view_mode => $display) {
-        if (isset($values[$view_mode])) {
-          $instance['display'][$view_mode] = array_merge($instance['display'][$view_mode], $values[$view_mode]);
-        }
+  $entity_type = $form['#entity_type'];
+  $bundle = $form['#bundle'];
+  $view_mode = $form['#view_mode'];
+
+  // Save data for 'regular' fields.
+  foreach ($form['#fields'] as $field_name) {
+    $instance = field_info_instance($entity_type, $field_name, $bundle);
+    $instance['display'][$view_mode] = $form_values['settings'][$field_name];
+    field_update_instance($instance);
+  }
+
+  // Get current bundle settings.
+  $bundle_settings = field_bundle_settings($entity_type, $bundle);
+
+  // Save data for 'extra' fields.
+  foreach ($form['#extra'] as $name) {
+    $bundle_settings['extra_fields']['display'][$name][$view_mode] = array(
+      'weight' => $form_values['settings'][$name]['weight'],
+      'visible' => $form_values['settings'][$name]['type'] == 'visible',
+    );
+  }
+
+  // Save view modes data.
+  if ($view_mode == 'default') {
+    $entity_info = entity_get_info($entity_type);
+    foreach ($form_values['view_modes_custom'] as $view_mode_name => $value) {
+      // Display a message for each view mode newly configured to use custom
+      // settings.
+      if (!empty($value) && empty($bundle_settings['view_modes'][$view_mode_name]['custom_settings'])) {
+        $view_mode_label = $entity_info['view modes'][$view_mode_name]['label'];
+        $path = _field_ui_bundle_admin_path($entity_type, $bundle) . "/display/$view_mode_name";
+        drupal_set_message(t('The %view_mode mode now uses custom display settings. You might want to <a href="@url">configure them</a>.', array('%view_mode' => $view_mode_label, '@url' => url($path))));
       }
-      field_update_instance($instance);
+      $bundle_settings['view_modes'][$view_mode_name]['custom_settings'] = !empty($value);
     }
   }
+
+  // Save updated bundle settings.
+  field_bundle_settings($entity_type, $bundle, $bundle_settings);
+
   drupal_set_message(t('Your settings have been saved.'));
 }
 
diff --git a/modules/field_ui/field_ui.css b/modules/field_ui/field_ui.css
index 2cc52736bd6a768dd4fb38ba2307a720ba3281d5..43d9b78f6676e183ce7ac396876097929d900a4a 100644
--- a/modules/field_ui/field_ui.css
+++ b/modules/field_ui/field_ui.css
@@ -16,3 +16,10 @@
   padding-bottom: .5em;
 }
 
+/* Manage display */
+.field-display-overview tr.region-title td {
+  font-weight: bold;
+}
+.field-display-overview tr.region-populated {
+  display: none;
+}
diff --git a/modules/field_ui/field_ui.js b/modules/field_ui/field_ui.js
index b8b8e484bbdcbfdad82adf1a4907a098b983b592..02b8b79ce49d72f7f8154f6425378939685c2165 100644
--- a/modules/field_ui/field_ui.js
+++ b/modules/field_ui/field_ui.js
@@ -81,4 +81,143 @@ jQuery.fn.fieldPopulateOptions = function (options, selected) {
   });
 };
 
+/**
+ * Moves a field in the display settings table from visible to hidden.
+ *
+ * This behavior is dependent on the tableDrag behavior, since it uses the
+ * objects initialized in that behavior to update the row.
+ */
+Drupal.behaviors.fieldManageDisplayDrag = {
+  attach: function (context, settings) {
+    // tableDrag is required for this behavior.
+    if (!$('table.field-display-overview', context).length || typeof Drupal.tableDrag == 'undefined') {
+      return;
+    }
+
+    var defaultFormatters = Drupal.settings.fieldDefaultFormatters;
+    var tableDrag = Drupal.tableDrag['field-display-overview'];
+
+    // Add a handler for when a row is swapped, update empty regions.
+    tableDrag.row.prototype.onSwap = function (swappedRow) {
+      checkEmptyRegions(this.table, this);
+    };
+
+    // Add a handler to update the formatter selector when a row is dropped in
+    // or out of the 'Hidden' section.
+    tableDrag.onDrop = function () {
+      var dragObject = this;
+      var regionRow = $(dragObject.rowObject.element).prevAll('tr.region-message').get(0);
+      var visibility = regionRow.className.replace(/([^ ]+[ ]+)*region-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+
+      // Update the 'format' selector if the visibility changed.
+      var $select = $('select.field-formatter-type', dragObject.rowObject.element);
+      var oldVisibility = $select[0].className.replace(/([^ ]+[ ]+)*field-display-([^ ]+)([ ]+[^ ]+)*/, '$2');
+      if (visibility != oldVisibility) {
+        $select.removeClass('field-display-' + oldVisibility).addClass('field-display-' + visibility);
+
+        // Update the selected formatter if coming from an actual drag.
+        if (!$select.data('noUpdate')) {
+          if (visibility == 'visible') {
+            // Restore the formatter back to the previously selected one if
+            // available, or to the default formatter.
+            var value = $select.data('oldFormatter');
+            if (typeof value == 'undefined') {
+              // Extract field name from the name of the select.
+              var fieldName = $select[0].className.match(/\bfield-name-(\S+)\b/)[1].replace('-', '_');
+              // Pseudo-fields do not have an entry in the defaultFormatters
+              // array, we just return to 'visible' for those.
+              value = (fieldName in defaultFormatters) ? defaultFormatters[fieldName] : 'visible';
+            }
+            $select.data('oldFormatter', value);
+          }
+          else {
+            var value = 'hidden';
+          }
+          $select.val(value);
+        }
+        $select.removeData('noUpdate');
+      }
+    };
+
+    // Add the behavior to each formatter select list.
+    $('select.field-formatter-type', context).once('field-formatter-type', function () {
+      // Initialize 'previously selected formatter' as the incoming value.
+      if ($(this).val() != 'hidden') {
+        $(this).data('oldFormatter', $(this).val());
+      }
+
+      // Add change listener.
+      $(this).change(function (event) {
+        var $select = $(this);
+        var value = $select.val();
+
+        // Keep track of the last selected formatter.
+        if (value != 'hidden') {
+          $select.data('oldFormatter', value);
+        }
+
+        var visibility = (value == 'hidden') ? 'hidden' : 'visible';
+        var oldVisibility = $select[0].className.replace(/([^ ]+[ ]+)*field-display-([^ ]+)([ ]+[^ ]+)*/, '$2');
+        if (visibility != oldVisibility) {
+          // Prevent the onDrop handler from overriding the selected option.
+          $select.data('noUpdate', true);
+
+          // Make our new row and select field.
+          var $row = $(this).parents('tr:first');
+          var $table = $(this).parents('table');
+          var tableDrag = Drupal.tableDrag[$table.attr('id')];
+          tableDrag.rowObject = new tableDrag.row($row);
+
+          // Move the row at the bottom of the new section.
+          if (visibility == 'hidden') {
+            $('tr:last', tableDrag.table).after($row);
+          }
+          else {
+            $('tr.region-title-hidden', tableDrag.table).before($row);
+          }
+
+          // Manually update weights and restripe.
+          tableDrag.updateFields($row.get(0));
+          tableDrag.rowObject.changed = true;
+          if (tableDrag.oldRowElement) {
+            $(tableDrag.oldRowElement).removeClass('drag-previous');
+          }
+          tableDrag.oldRowElement = $row.get(0);
+          tableDrag.restripeTable();
+          tableDrag.rowObject.markChanged();
+          tableDrag.oldRowElement = $row;
+          $row.addClass('drag-previous');
+
+          // Modify empty regions with added or removed fields.
+          checkEmptyRegions($table, tableDrag.rowObject);
+        }
+
+        // Remove focus from selectbox.
+        $select.get(0).blur();
+      });
+    });
+
+    var checkEmptyRegions = function ($table, rowObject) {
+      $('tr.region-message', $table).each(function () {
+        // If the dragged row is in this region, but above the message row, swap
+        // it down one space.
+        if ($(this).prev('tr').get(0) == rowObject.element) {
+          // Prevent a recursion problem when using the keyboard to move rows up.
+          if ((rowObject.method != 'keyboard' || rowObject.direction == 'down')) {
+            rowObject.swap('after', this);
+          }
+        }
+        // This region has become empty.
+        if ($(this).next('tr').is(':not(.draggable)') || $(this).next('tr').length == 0) {
+          $(this).removeClass('region-populated').addClass('region-empty');
+        }
+        // This region has become populated.
+        else if ($(this).is('.region-empty')) {
+          $(this).removeClass('region-empty').addClass('region-populated');
+        }
+      });
+    };
+  }
+};
+
 })(jQuery);
diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module
index 3bb5cd886e74739e9b70f0a8fdcdf3cec8be0660..470abe6d789bfda47643f783f816a08431a46431 100644
--- a/modules/field_ui/field_ui.module
+++ b/modules/field_ui/field_ui.module
@@ -48,6 +48,24 @@ function field_ui_help($path, $arg) {
   }
 }
 
+/**
+ * Implements hook_theme().
+ */
+function field_ui_theme() {
+  return array(
+    'field_ui_field_overview_form' => array(
+      'render element' => 'form',
+      'file' => 'field_ui.admin.inc',
+      'template' => 'field_ui-field-overview-form',
+    ),
+    'field_ui_display_overview_table' => array(
+      'render element' => 'elements',
+      'file' => 'field_ui.admin.inc',
+      'template' => 'field_ui-display-overview-table',
+    ),
+  );
+}
+
 /**
  * Implements hook_menu().
  */
@@ -66,10 +84,11 @@ function field_ui_menu() {
   if (defined('MAINTENANCE_MODE')) {
     return $items;
   }
+
   // Create tabs for all possible bundles.
-  foreach (entity_get_info() as $entity_type => $info) {
-    if ($info['fieldable']) {
-      foreach ($info['bundles'] as $bundle_name => $bundle_info) {
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if ($entity_info['fieldable']) {
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
         if (isset($bundle_info['admin'])) {
           // Extract path information from the bundle.
           $path = $bundle_info['admin']['path'];
@@ -92,7 +111,12 @@ function field_ui_menu() {
           // items below.
           $field_position = count(explode('/', $path)) + 1;
 
+          // Extract access information, providing defaults.
           $access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));
+          $access += array(
+            'access callback' => 'user_access',
+            'access arguments' => array('administer site configuration'),
+          );
 
           $items["$path/fields"] = array(
             'title' => 'Manage fields',
@@ -145,24 +169,38 @@ function field_ui_menu() {
             'file' => 'field_ui.admin.inc',
           ) + $access;
 
-          // 'Manage display' tab and context secondary tabs.
+          // 'Manage display' tab.
           $items["$path/display"] = array(
             'title' => 'Manage display',
             'page callback' => 'drupal_get_form',
-            'page arguments' => array('field_ui_display_overview_form', $entity_type, $bundle_arg),
+            'page arguments' => array('field_ui_display_overview_form', $entity_type, $bundle_arg, 'default'),
             'type' => MENU_LOCAL_TASK,
             'weight' => 2,
             'file' => 'field_ui.admin.inc',
           ) + $access;
-          $tabs = field_ui_view_modes_tabs($entity_type);
-          foreach ($tabs as $key => $tab) {
-            $items["$path/display/$key"] = array(
-              'title' => $tab['title'],
-              'page arguments' => array('field_ui_display_overview_form', $entity_type, $bundle_arg, $key),
-              'type' => $key == 'basic' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
-              'weight' => $key == 'basic' ? 0 : 1,
+
+          // View modes secondary tabs.
+          // The same base $path for the menu item (with a placeholder) can be
+          // used for all bundles of a given entity type; but depending on
+          // administrator settings, each bundle has a different set of view
+          // modes available for customisation. So we define menu items for all
+          // view modes, and use an access callback to determine which ones are
+          // actually visible for a given bundle.
+          $weight = 0;
+          $view_modes = array('default' => array('label' => t('Default'))) + $entity_info['view modes'];
+          foreach ($view_modes as $view_mode => $view_mode_info) {
+            $items["$path/display/$view_mode"] = array(
+              'title' => $view_mode_info['label'],
+              'page arguments' => array('field_ui_display_overview_form', $entity_type, $bundle_arg, $view_mode),
+              // The access callback needs to check both the current 'custom
+              // display' setting for the view mode, and the overall access
+              // rules for the bundle admin pages.
+              'access callback' => '_field_ui_view_mode_menu_access',
+              'access arguments' => array_merge(array($entity_type, $bundle_arg, $view_mode, $access['access callback']), $access['access arguments']),
+              'type' => ($view_mode == 'default' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK),
+              'weight' => ($view_mode == 'default' ? -10 : $weight++),
               'file' => 'field_ui.admin.inc',
-            ) + $access;
+            );
           }
         }
       }
@@ -219,100 +257,35 @@ function field_ui_menu_title($instance) {
 }
 
 /**
- * Implements hook_theme().
+ * Menu access callback for the 'view mode display settings' pages.
  */
-function field_ui_theme() {
-  return array(
-    'field_ui_field_overview_form' => array(
-      'render element' => 'form',
-      'file' => 'field_ui.admin.inc',
-      'template' => 'field_ui-field-overview-form',
-    ),
-    'field_ui_display_overview_form' => array(
-      'render element' => 'form',
-      'file' => 'field_ui.admin.inc',
-      'template' => 'field_ui-display-overview-form',
-    ),
-  );
-}
+function _field_ui_view_mode_menu_access($entity_type, $bundle, $view_mode, $access_callback) {
+  // First, determine visibility according to the 'use custom display'
+  // setting for the view mode.
+  $bundle = field_extract_bundle($entity_type, $bundle);
+  $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
+  $visibility = ($view_mode == 'default') || !empty($view_mode_settings[$view_mode]['custom_settings']);
 
-/**
- * Returns information about tab groups for view modes on an entity type.
- *
- * On the 'Manage display' page, an administrator can manage the display of
- * fields for each view mode for an entity type. The view modes are organized
- * into tabs. This function returns the list of entity types to display on
- * each tab, as well as the titles of the tabs.
- *
- * @param $entity_type
- *   The type of entity to return tab information for.
- * @param $tab_selector
- *   If not NULL, return only information for this particular tab; if NULL,
- *   return all tab information.
- *
- * @return
- *   Array of information about the tabs to display. The keys are internal-use
- *   tab names and the values are arrays of tab information, with the following
- *   elements:
- *   - 'title': Human-readable title of the tab.
- *   - 'view modes': Array of view modes for this entity type that should
- *     be displayed on this tab.
- *
- * @see hook_field_ui_view_modes_tabs()
- *
- * @todo Remove this completely and use vertical tabs?
- */
-function field_ui_view_modes_tabs($entity_type, $tab_selector = NULL) {
-  $info = &drupal_static(__FUNCTION__);
-
-  if (!isset($info[$entity_type])) {
-    $info[$entity_type] = module_invoke_all('field_ui_view_modes_tabs', $entity_type);
-    // Filter out inactive modes.
-    $entity_info = entity_get_info($entity_type);
-    foreach ($info[$entity_type] as $tab => $values) {
-      $modes = array();
-      foreach ($info[$entity_type][$tab]['view modes'] as $mode) {
-        if (isset($entity_info['view modes'][$mode])) {
-          $modes[] = $mode;
-        }
-      }
-      if ($modes) {
-        $info[$entity_type][$tab]['view modes'] = $modes;
+  // Then, determine access according to the $access parameter. This duplicates
+  // part of _menu_check_access().
+  if ($visibility) {
+    // Grab the variable 'access arguments' part.
+    $args = array_slice(func_get_args(), 4);
+    $callback = empty($access_callback) ? 0 : trim($access_callback);
+    if (is_numeric($callback)) {
+      return (bool) $callback;
+    }
+    else {
+      // As call_user_func_array() is quite slow and user_access is a very
+      // common callback, it is worth making a special case for it.
+      if ($access_callback == 'user_access') {
+        return (count($args) == 1) ? user_access($args[0]) : user_access($args[0], $args[1]);
       }
-      else {
-        unset($info[$entity_type][$tab]);
+      elseif (function_exists($access_callback)) {
+        return call_user_func_array($access_callback, $args);
       }
     }
   }
-  if ($tab_selector) {
-    return isset($info[$entity_type][$tab_selector]) ? $info[$entity_type][$tab_selector]['view modes'] : array();
-  }
-  return $info[$entity_type];
-}
-
-/**
- * Implements hook_field_ui_view_modes_tabs() on behalf of other core modules.
- */
-function field_ui_field_ui_view_modes_tabs() {
-  $modes = array(
-    'basic' => array(
-      'title' => t('Basic'),
-      'view modes' => array('teaser', 'full'),
-    ),
-    'rss' => array(
-      'title' => t('RSS'),
-      'view modes' => array('rss'),
-    ),
-    'print' => array(
-      'title' => t('Print'),
-      'view modes' => array('print'),
-    ),
-    'search' => array(
-      'title' => t('Search'),
-      'view modes' => array('search_index', 'search_result'),
-    ),
-  );
-  return $modes;
 }
 
 /**
@@ -324,31 +297,6 @@ function field_ui_field_attach_create_bundle($entity_type, $bundle) {
   variable_set('menu_rebuild_needed', TRUE);
 }
 
-/**
- * Implements hook_field_attach_rename_bundle().
- */
-function field_ui_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
-  if ($bundle_old !== $bundle_new) {
-    $extra_weights = variable_get('field_extra_weights', array());
-    if (isset($info[$entity_type][$bundle_old])) {
-      $extra_weights[$entity_type][$bundle_new] = $extra_weights[$entity_type][$bundle_old];
-      unset($extra_weights[$entity_type][$bundle_old]);
-      variable_set('field_extra_weights', $extra_weights);
-    }
-  }
-}
-
-/**
- * Implements hook_field_attach_delete_bundle().
- */
-function field_ui_field_attach_delete_bundle($entity_type, $bundle) {
-  $extra_weights = variable_get('field_extra_weights', array());
-  if (isset($extra_weights[$entity_type][$bundle])) {
-    unset($extra_weights[$entity_type][$bundle]);
-    variable_set('field_extra_weights', $extra_weights);
-  }
-}
-
 /**
  * Helper function to create the right administration path for a bundle.
  */
diff --git a/modules/forum/forum.install b/modules/forum/forum.install
index d23725164a61b47ff9275675ae03adceed7798a7..1a488327c91006220071f36077e60b809b0988ad 100644
--- a/modules/forum/forum.install
+++ b/modules/forum/forum.install
@@ -65,6 +65,16 @@ function forum_enable() {
       'widget' => array(
         'type' => 'options_select',
       ),
+      'display' => array(
+        'default' => array(
+          'type' => 'taxonomy_term_reference_link',
+          'weight' => 10,
+        ),
+        'teaser' => array(
+          'type' => 'taxonomy_term_reference_link',
+          'weight' => 10,
+        ),
+      ),
     );
     field_create_instance($instance);
 
diff --git a/modules/image/image.test b/modules/image/image.test
index 74d33e9dbb563c90002e86dd65ca4b362ee109c9..e03b5d8eb7390d01cc0acb7603c45edc7744bccc 100644
--- a/modules/image/image.test
+++ b/modules/image/image.test
@@ -592,7 +592,7 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase {
     // Create an image field that uses the new style.
     $field_name = strtolower($this->randomName(10));
     $instance = $this->createImageField($field_name, 'article');
-    $instance['display']['full']['type'] = 'image__' . $style_name;
+    $instance['display']['default']['type'] = 'image__' . $style_name;
     field_update_instance($instance);
 
     // Create a new node with an image attached.
@@ -662,21 +662,21 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
 
     // Test the image linked to file formatter.
     $instance = field_info_instance('node', $field_name, 'article');
-    $instance['display']['full']['type'] = 'image_link_file';
+    $instance['display']['default']['type'] = 'image_link_file';
     field_update_instance($instance);
     $default_output = l(theme('image', $image_info), file_create_url($image_uri), array('html' => TRUE));
     $this->drupalGet('node/' . $nid);
     $this->assertRaw($default_output, t('Image linked to file formatter displaying correctly on full node view.'));
 
     // Test the image linked to content formatter.
-    $instance['display']['full']['type'] = 'image_link_content';
+    $instance['display']['default']['type'] = 'image_link_content';
     field_update_instance($instance);
     $default_output = l(theme('image', $image_info), 'node/' . $nid, array('html' => TRUE, 'attributes' => array('class' => 'active')));
     $this->drupalGet('node/' . $nid);
     $this->assertRaw($default_output, t('Image linked to content formatter displaying correctly on full node view.'));
 
     // Test the image style 'thumbnail' formatter.
-    $instance['display']['full']['type'] = 'image__thumbnail';
+    $instance['display']['default']['type'] = 'image__thumbnail';
     field_update_instance($instance);
     // Ensure the derrivative image is generated so we do not have to deal with
     // image style callback paths.
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index 6f82b9e3e61d6140aa3011f6bfe1d12f71c00fe5..ee73054fa9295a456ff8d68c415bd9b9b47ed686 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -1917,16 +1917,6 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
     $this->drupalGet("node/$node->nid");
     $body = $this->xpath('//div[@id=:id]//div[@property="content:encoded"]/p', array(':id' => 'node-' . $node->nid));
     $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body is correctly showed.');
-
-    $settings['body[full][type]'] = 'hidden';
-    $this->drupalPost('admin/structure/types/manage/page/display', $settings, t('Save'));
-    $select = $this->xpath('//select[@id="edit-body-full-type"]/option[@selected="selected"]');
-    // Check if body display is actually "hidden" for the "full" view mode.
-    $this->assertEqual(current($select), '<Hidden>', 'Body display is actually "hidden" for the "full" view mode');
-    $this->drupalGet("node/$node->nid");
-    // Check if node body is not showed.
-    $body = $this->xpath('//div[@id=:id]//div[@property="content:encoded"]/p', array(':id' => 'node-' . $node->nid));
-    $this->assertFalse(is_array($body), 'Body correctly not showed.');
   }
 }
 
diff --git a/modules/node/node.api.php b/modules/node/node.api.php
index d340d237e114f6c38fe5e16c534c25e334c1a133..4bf678029cbc22773143b11dfb217795d9047357 100644
--- a/modules/node/node.api.php
+++ b/modules/node/node.api.php
@@ -1142,7 +1142,7 @@ function hook_validate($node, &$form) {
  *
  * @ingroup node_api_hooks
  */
-function hook_view($node, $view_mode = 'full') {
+function hook_view($node, $view_mode) {
   if (node_is_page($node)) {
     $breadcrumb = array();
     $breadcrumb[] = l(t('Home'), NULL);
diff --git a/modules/node/node.module b/modules/node/node.module
index 4de27a479e0012cb5ab0ddecec179309599668fe..bc59ea9b3b963612fdc2fb80169bcd7221aa4091 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -189,12 +189,15 @@ function node_entity_info() {
       'view modes' => array(
         'full' => array(
           'label' => t('Full content'),
+          'custom settings' => FALSE,
         ),
         'teaser' => array(
           'label' => t('Teaser'),
+          'custom settings' => TRUE,
         ),
         'rss' => array(
           'label' => t('RSS'),
+          'custom settings' => FALSE,
         ),
       ),
     ),
@@ -206,9 +209,11 @@ function node_entity_info() {
     $return['node']['view modes'] += array(
       'search_index' => array(
         'label' => t('Search index'),
+        'custom settings' => FALSE,
       ),
       'search_result' => array(
         'label' => t('Search result'),
+        'custom settings' => FALSE,
       ),
     );
   }
@@ -230,6 +235,16 @@ function node_entity_info() {
   return $return;
 }
 
+/**
+ * Implements hook_field_display_ENTITY_TYPE_alter().
+ */
+function node_field_display_node_alter(&$display, $context) {
+  // Hide field labels in search index.
+  if ($context['view_mode'] == 'search_index') {
+    $display['label'] = 'hidden';
+  }
+}
+
 /**
  * Entity uri callback.
  */
@@ -562,10 +577,8 @@ function node_add_body_field($type, $label = 'Body') {
       'label' => $label,
       'widget_type' => 'text_textarea_with_summary',
       'settings' => array('display_summary' => TRUE),
-
-      // Define default formatters for the teaser and full view.
       'display' => array(
-        'full' => array(
+        'default' => array(
           'label' => 'hidden',
           'type' => 'text_default',
         ),
@@ -588,10 +601,12 @@ function node_field_extra_fields() {
   foreach (node_type_get_types() as $type) {
     if ($type->has_title) {
       $extra['node'][$type->type] = array(
-        'title' => array(
-          'label' => $type->title_label,
-          'description' => t('Node module element.'),
-          'weight' => -5,
+        'form' => array(
+          'title' => array(
+            'label' => $type->title_label,
+            'description' => t('Node module element'),
+            'weight' => -5,
+          ),
         ),
       );
     }
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 8a606015161164a3c9c7bcd9779afd2859758e33..7a8c33395942865de236756d86c9f4c5bc30f141 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -208,16 +208,30 @@ function poll_node_info() {
  */
 function poll_field_extra_fields() {
   $extra['node']['poll'] = array(
-    'choice_wrapper' => array(
-      'label' => t('Poll choices'),
-      'description' => t('Poll module choices.'),
-      'weight' => -4,
-    ),
-    'settings' => array(
-      'label' => t('Poll settings'),
-      'description' => t('Poll module settings.'),
-      'weight' => -3,
+    'form' => array(
+      'choice_wrapper' => array(
+        'label' => t('Poll choices'),
+        'description' => t('Poll choices'),
+        'weight' => -4,
+      ),
+      'settings' => array(
+        'label' => t('Poll settings'),
+        'description' => t('Poll module settings'),
+        'weight' => -3,
+      ),
     ),
+    'display' => array(
+      'poll_view_voting' => array(
+        'label' => t('Poll vote'),
+        'description' => t('Poll vote'),
+        'weight' => 0,
+      ),
+      'poll_view_results' => array(
+        'label' => t('Poll results'),
+        'description' => t('Poll results'),
+        'weight' => 0,
+      ),
+    )
   );
 
   return $extra;
@@ -624,7 +638,7 @@ function poll_block_latest_poll_view($node) {
 /**
  * Implements hook_view().
  */
-function poll_view($node, $view_mode = 'full') {
+function poll_view($node, $view_mode) {
   global $user;
   $output = '';
 
diff --git a/modules/rdf/rdf.test b/modules/rdf/rdf.test
index 127f6a40e9912bfbb5c6b93b53c59d078370c3ad..d77f8968f9fdf3f4332d740d17de77d81bf8d465 100644
--- a/modules/rdf/rdf.test
+++ b/modules/rdf/rdf.test
@@ -127,18 +127,27 @@ class RdfRdfaMarkupTestCase extends DrupalWebTestCase {
     $langcode = LANGUAGE_NONE;
     $bundle_name = "article";
 
-    // Create file field.
-    $file_field = 'file_test';
-    $edit = array(
-      '_add_new_field[label]' => $file_field,
-      '_add_new_field[field_name]' => $file_field,
-      '_add_new_field[type]' => 'file',
-      '_add_new_field[widget_type]' => 'file_generic',
+    $field_name = 'file_test';
+    $field = array(
+      'field_name' => $field_name,
+      'type' => 'file',
     );
-    $this->drupalPost('admin/structure/types/manage/' . $bundle_name . '/fields',  $edit, t('Save'));
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'node',
+      'bundle' => $bundle_name,
+      'display' => array(
+        'teaser' => array(
+          'type' => 'file_default',
+        ),
+      ),
+    );
+    field_create_instance($instance);
+
     // Set the RDF mapping for the new field.
     $rdf_mapping = rdf_mapping_load('node', $bundle_name);
-    $rdf_mapping += array('field_' . $file_field => array('predicates' => array('rdfs:seeAlso'), 'type' => 'rel'));
+    $rdf_mapping += array($field_name => array('predicates' => array('rdfs:seeAlso'), 'type' => 'rel'));
     $rdf_mapping_save = array('mapping' => $rdf_mapping, 'type' => 'node', 'bundle' => $bundle_name);
     rdf_mapping_save($rdf_mapping_save);
 
@@ -152,7 +161,7 @@ class RdfRdfaMarkupTestCase extends DrupalWebTestCase {
 
     // Create an array for drupalPost with the field names as the keys and
     // the uris for the test files as the values.
-    $edit = array("files[field_" . $file_field . "_" . $langcode . "_0]" => drupal_realpath($file->uri),
+    $edit = array("files[" . $field_name . "_" . $langcode . "_0]" => drupal_realpath($file->uri),
                   "files[" . $image_field . "_" . $langcode . "_0]" => drupal_realpath($image->uri));
 
     // Create node and save, then edit node to upload files.
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index df083119936023ea7685855f7d1626ff9c03e10f..32c55cf92d9a67465212829b448f3f41a32e1457 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -140,9 +140,21 @@ function hook_hook_info_alter(&$hooks) {
  *     ('full' mode), on the home page or taxonomy listings ('teaser' mode), or
  *     in an RSS feed ('rss' mode). Modules taking part in the display of the
  *     entity (notably the Field API) can adjust their behavior depending on
- *     the requested view mode. Keys of the array are view mode names. Each
- *     view mode is described by an array with the following key/value pairs:
+ *     the requested view mode. An additional 'default' view mode is available
+ *     for all entity types. This view mode is not intended for actual entity
+ *     display, but holds default display settings. For each available view
+ *     mode, administrators can configure whether it should use its own set of
+ *     field display settings, or just replicate the settings of the 'default'
+ *     view mode, thus reducing the amount of display configurations to keep
+ *     track of. Keys of the array are view mode names. Each view mode is
+ *     described by an array with the following key/value pairs:
  *     - label: The human-readable name of the view mode
+ *     - custom settings: A boolean specifying whether the view mode should by
+ *     default use its own custom field display settings. If FALSE, entities
+ *     displayed in this view mode will reuse the 'default' display settings by
+ *     default (e.g. right after the module exposing the view mode is enabled),
+ *     but administrators can later use the Field UI to apply custom display
+ *     settings specific to the view mode.
  */
 function hook_entity_info() {
   $return = array(
@@ -151,7 +163,7 @@ function hook_entity_info() {
       'controller class' => 'NodeController',
       'base table' => 'node',
       'revision table' => 'node_revision',
-      'path callback' => 'node_path',
+      'uri callback' => 'node_uri',
       'fieldable' => TRUE,
       'entity keys' => array(
         'id' => 'nid',
@@ -164,13 +176,16 @@ function hook_entity_info() {
       'bundles' => array(),
       'view modes' => array(
         'full' => array(
-          'label' => t('Full node'),
+          'label' => t('Full content'),
+          'custom settings' => FALSE,
         ),
         'teaser' => array(
           'label' => t('Teaser'),
+          'custom settings' => TRUE,
         ),
         'rss' => array(
           'label' => t('RSS'),
+          'custom settings' => FALSE,
         ),
       ),
     ),
@@ -182,9 +197,11 @@ function hook_entity_info() {
     $return['node']['view modes'] += array(
       'search_index' => array(
         'label' => t('Search index'),
+        'custom settings' => FALSE,
       ),
       'search_result' => array(
         'label' => t('Search result'),
+        'custom settings' => FALSE,
       ),
     );
   }
diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install
index 9e8153c1acfd3ced99b655b69efb8220545a256f..35fbca2c971d8fb3f418661121da77613137116b 100644
--- a/modules/taxonomy/taxonomy.install
+++ b/modules/taxonomy/taxonomy.install
@@ -380,6 +380,16 @@ function taxonomy_update_7004() {
         'widget' => array(
           'type' => $vocabulary->tags ? 'taxonomy_autocomplete' : 'select',
         ),
+        'display' => array(
+          'default' => array(
+            'type' => 'taxonomy_term_reference_link',
+            'weight' => 10,
+          ),
+          'teaser' => array(
+            'type' => 'taxonomy_term_reference_link',
+            'weight' => 10,
+          ),
+        ),
       );
       field_create_instance($instance);
     }
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index ab98ebddae2b5f0bd8bb44d68463ff6cc2da2db0..6dd9b36c1d422cdb3b4769e5392f385526588d18 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -101,6 +101,7 @@ function taxonomy_entity_info() {
         // @todo View mode for display as a field (when attached to nodes etc).
         'full' => array(
           'label' => t('Taxonomy term page'),
+          'custom settings' => FALSE,
         ),
       ),
     ),
@@ -146,16 +147,25 @@ function taxonomy_field_extra_fields() {
   $info = entity_get_info('taxonomy_term');
   foreach (array_keys($info['bundles']) as $bundle) {
     $return['taxonomy_term'][$bundle] = array(
-      'name' => array(
-        'label' => t('Name'),
-        'description' => t('Term name textfield'),
-        'weight' => -5,
+      'form' => array(
+        'name' => array(
+          'label' => t('Name'),
+          'description' => t('Term name textfield'),
+          'weight' => -5,
+        ),
+        'description' => array(
+          'label' => t('Description'),
+          'description' => t('Term description textarea'),
+          'weight' => 0,
+        ),
+      ),
+      'display' => array(
+        'description' => array(
+          'label' => t('Description'),
+          'description' => t('Term description'),
+          'weight' => 0,
+        ),
       ),
-      'description' => array(
-        'label' => t('Description'),
-        'description' => t('Term description textarea'),
-        'weight' => 0,
-      )
     );
   }
 
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index 47285f78bd79513de5356175fefb7f4a12909916..d60f1e616425a5929431612375f4875fb87eb660 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -347,7 +347,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
         'type' => 'options_select',
       ),
       'display' => array(
-        'full' => array(
+        'default' => array(
           'type' => 'taxonomy_term_reference_link',
         ),
       ),
@@ -848,7 +848,12 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
       'label' => $this->randomName() . '_label',
       'widget' => array(
         'type' => 'options_select',
-      )
+      ),
+      'display' => array(
+        'full' => array(
+          'type' => 'taxonomy_term_reference_link',
+        ),
+      ),
     );
     field_create_instance($this->instance);
 
@@ -873,7 +878,7 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
     $entity = field_test_entity_test_load($id);
     $entities = array($id => $entity);
     field_attach_prepare_view($entity_type, $entities, 'full');
-    $entity->content = field_attach_view($entity_type, $entity);
+    $entity->content = field_attach_view($entity_type, $entity, 'full');
     $this->content = drupal_render($entity->content);
     $this->assertText($term->name, t('Term name is displayed'));
   }
@@ -921,7 +926,7 @@ class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
         'type' => 'options_select',
       ),
       'display' => array(
-        'full' => array(
+        'default' => array(
           'type' => 'taxonomy_term_reference_link',
         ),
       ),
diff --git a/modules/user/user.module b/modules/user/user.module
index 703ad19ce4edcb8f67650af3ad6591dd6ab740e6..0256040b752d93d902f710392fd630fd36e46787 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -146,6 +146,7 @@ function user_entity_info() {
       'view modes' => array(
         'full' => array(
           'label' => t('User account'),
+          'custom settings' => FALSE,
         ),
       ),
     ),
@@ -167,20 +168,24 @@ function user_uri($user) {
  */
 function user_field_extra_fields() {
   $return['user']['user'] = array(
-    'account' => array(
-      'label' => 'User name and password',
-      'description' => t('User module account form elements'),
-      'weight' => -10,
-    ),
-    'timezone' => array(
-      'label' => 'Timezone',
-      'description' => t('User module timezone form element.'),
-      'weight' => 6,
+    'form' => array(
+      'account' => array(
+        'label' => 'User name and password',
+        'description' => t('User module account form elements'),
+        'weight' => -10,
+      ),
+      'timezone' => array(
+        'label' => 'Timezone',
+        'description' => t('User module timezone form element.'),
+        'weight' => 6,
+      ),
     ),
-    'summary' => array(
-      'label' => 'History',
-      'description' => t('User module history view element.'),
-      'weight' => 5,
+    'display' => array(
+      'summary' => array(
+        'label' => 'History',
+        'description' => t('User module history view element.'),
+        'weight' => 5,
+      ),
     ),
   );
 
diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install
index 8175417cd3a34b3e247275f281542a731a535a59..79e85c7ad07779d2bafae97704b939d699dc47a9 100644
--- a/profiles/standard/standard.install
+++ b/profiles/standard/standard.install
@@ -310,6 +310,16 @@ function standard_install() {
       'type' => 'taxonomy_autocomplete',
       'weight' => 4,
     ),
+    'display' => array(
+      'default' => array(
+        'type' => 'taxonomy_term_reference_link',
+        'weight' => 10,
+      ),
+      'teaser' => array(
+        'type' => 'taxonomy_term_reference_link',
+        'weight' => 10,
+      ),
+    ),
   );
   field_create_instance($instance);
 
@@ -367,34 +377,14 @@ function standard_install() {
     ),
 
     'display' => array(
-      'full' => array(
+      'default' => array(
         'label' => 'hidden',
         'type' => 'image__large',
-        'settings' => array(),
         'weight' => -1,
       ),
       'teaser' => array(
         'label' => 'hidden',
         'type' => 'image_link_content__medium',
-        'settings' => array(),
-        'weight' => -1,
-      ),
-      'rss' => array(
-        'label' => 'hidden',
-        'type' => 'image__large',
-        'settings' => array(),
-        'weight' => -1,
-      ),
-      'search_index' => array(
-        'label' => 'hidden',
-        'type' => 'image__large',
-        'settings' => array(),
-        'weight' => -1,
-      ),
-      'search_results' => array(
-        'label' => 'hidden',
-        'type' => 'image__large',
-        'settings' => array(),
         'weight' => -1,
       ),
     ),