diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 3196509..820d8e6 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -311,17 +311,18 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL)
 }
 
 /**
- * Implements hook_form_FORM_ID_alter() for field_ui_field_overview_form.
+ * Implements hook_form_FORM_ID_alter() for field_ui_field_storage_add_form.
  */
-function comment_form_field_ui_field_overview_form_alter(&$form, FormStateInterface $form_state) {
+function comment_form_field_ui_field_storage_add_form_alter(&$form, FormStateInterface $form_state) {
   $request = \Drupal::request();
-  if ($form['#entity_type'] == 'comment' && $request->attributes->has('commented_entity_type')) {
+  if ($form['#entity_type_id'] == 'comment' && $request->attributes->has('commented_entity_type')) {
     $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($request->attributes->get('commented_entity_type'), $request->attributes->get('field_name'));
   }
-  $entity_type_id = $form['#entity_type'];
-  if (!_comment_entity_uses_integer_id($entity_type_id)) {
+  if (!_comment_entity_uses_integer_id($form['#entity_type_id'])) {
     // You cannot use comment fields on entity types with non-integer IDs.
-    unset($form['fields']['_add_new_field']['type']['#options']['comment']);
+    // @todo This looks very brittle, we should implement hook_field_presave()
+    // instead.
+    unset($form['field']['type']['#options']['comment']);
   }
 }
 
diff --git a/core/modules/comment/src/Tests/CommentNonNodeTest.php b/core/modules/comment/src/Tests/CommentNonNodeTest.php
index ccaa163..01fd2a7 100644
--- a/core/modules/comment/src/Tests/CommentNonNodeTest.php
+++ b/core/modules/comment/src/Tests/CommentNonNodeTest.php
@@ -408,24 +408,24 @@ public function testsNonIntegerIdEntities() {
       'administer entity_test_string_id fields',
     ));
     $this->drupalLogin($limited_user);
-    // Visit the Field UI overview.
-    $this->drupalGet('entity_test_string_id/structure/entity_test/fields');
+    // Visit the Field UI field add page.
+    $this->drupalGet('entity_test_string_id/structure/entity_test/add-field');
     // Ensure field isn't shown for string IDs.
-    $this->assertNoOption('edit-fields-add-new-field-type', 'comment');
+    $this->assertNoOption('edit-type', 'comment');
     // Ensure a core field type shown.
-    $this->assertOption('edit-fields-add-new-field-type', 'boolean');
+    $this->assertOption('edit-type', 'boolean');
 
     // Create a bundle for entity_test_no_id.
     entity_test_create_bundle('entity_test', 'Entity Test', 'entity_test_no_id');
     $this->drupalLogin($this->drupalCreateUser(array(
       'administer entity_test_no_id fields',
     )));
-    // Visit the Field UI overview.
-    $this->drupalGet('entity_test_no_id/structure/entity_test/fields');
+    // Visit the Field UI field add page.
+    $this->drupalGet('entity_test_no_id/structure/entity_test/add-field');
     // Ensure field isn't shown for empty IDs.
-    $this->assertNoOption('edit-fields-add-new-field-type', 'comment');
+    $this->assertNoOption('edit-type', 'comment');
     // Ensure a core field type shown.
-    $this->assertOption('edit-fields-add-new-field-type', 'boolean');
+    $this->assertOption('edit-type', 'boolean');
   }
 
 }
diff --git a/core/modules/contact/src/Tests/ContactSitewideTest.php b/core/modules/contact/src/Tests/ContactSitewideTest.php
index 53d8269..569b299 100644
--- a/core/modules/contact/src/Tests/ContactSitewideTest.php
+++ b/core/modules/contact/src/Tests/ContactSitewideTest.php
@@ -256,6 +256,8 @@ function testSiteWideContact() {
 
     $this->clickLink(t('Manage fields'), $i);
     $this->assertResponse(200);
+    $this->clickLink(t('Add field'));
+    $this->assertResponse(200);
 
     // Create a simple textfield.
     $field_name = Unicode::strtolower($this->randomMachineName());
diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php
index a89606c..f0896e9 100644
--- a/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php
+++ b/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php
@@ -55,11 +55,11 @@ public function testFieldAdminHandler() {
     $bundle_path = 'admin/structure/types/manage/' . $this->type;
 
     // First step: 'Add new field' on the 'Manage fields' page.
-    $this->drupalPostForm($bundle_path . '/fields', array(
-      'fields[_add_new_field][label]' => 'Test label',
-      'fields[_add_new_field][field_name]' => 'test',
-      'fields[_add_new_field][type]' => 'entity_reference',
-    ), t('Save'));
+    $this->drupalPostForm($bundle_path . '/add-field', array(
+      'label' => 'Test label',
+      'field_name' => 'test',
+      'type' => 'entity_reference',
+    ), t('Save and continue'));
 
     // Node should be selected by default.
     $this->assertFieldByName('field_storage[settings][target_type]', 'node');
@@ -192,11 +192,11 @@ public function createEntityReferenceField($target_type, $bundle = NULL) {
     $field_name = strtolower($this->randomMachineName());
 
     // Create the initial entity reference.
-    $this->drupalPostForm($bundle_path . '/fields', array(
-      'fields[_add_new_field][label]' => $this->randomMachineName(),
-      'fields[_add_new_field][field_name]' => $field_name,
-      'fields[_add_new_field][type]' => 'entity_reference',
-    ), t('Save'));
+    $this->drupalPostForm($bundle_path . '/add-field', array(
+      'label' => $this->randomMachineName(),
+      'field_name' => $field_name,
+      'type' => 'entity_reference',
+    ), t('Save and continue'));
 
     // Select the correct target type given in the parameters and save field settings.
     $this->drupalPostForm(NULL, array('field_storage[settings][target_type]' => $target_type), t('Save field settings'));
diff --git a/core/modules/field_ui/css/field_ui.admin.css b/core/modules/field_ui/css/field_ui.admin.css
index 29bef62..ede3d06 100644
--- a/core/modules/field_ui/css/field_ui.admin.css
+++ b/core/modules/field_ui/css/field_ui.admin.css
@@ -3,6 +3,16 @@
  * Stylesheet for the Field UI module.
  */
 
+/* Add new field page. */
+.field-ui-field-storage-add-form .field-type-wrapper .form-item {
+  float: left;
+  margin-right: 1em;
+  vertical-align: text-bottom;
+}
+.field-ui-field-storage-add-form .field-type-wrapper .form-type-item {
+  margin-top: 2.3em;
+}
+
 /* 'Manage fields' and 'Manage display' overviews */
 .field-ui-overview .add-new .label-input {
   float: left; /* LTR */
diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js
index 3fed9ef..ffbe499 100644
--- a/core/modules/field_ui/field_ui.js
+++ b/core/modules/field_ui/field_ui.js
@@ -7,6 +7,29 @@
 
   "use strict";
 
+  Drupal.behaviors.fieldUIFieldStorageAddForm = {
+    attach: function (context) {
+      var $fieldType = $(context).find('select[name="type"]');
+      var $existingField = $(context).find('select[name="existing_field_name"]');
+
+      // When the user selects a new field type, clear the "existing field"
+      // selection.
+      $fieldType.change(function () {
+        if ($(this).val() != '') {
+          $existingField.val('');
+        }
+      });
+
+      // When the user selects an existing field, clear the "new field type"
+      // selection.
+      $existingField.change(function () {
+        if ($(this).val() != '') {
+          $fieldType.val('').change();
+        }
+      });
+    }
+  };
+
   Drupal.behaviors.fieldUIDisplayOverview = {
     attach: function (context, settings) {
       $(context).find('table#field-display-overview').once('field-display-overview', function () {
diff --git a/core/modules/field_ui/field_ui.links.action.yml b/core/modules/field_ui/field_ui.links.action.yml
index dae1583..b03bac5 100644
--- a/core/modules/field_ui/field_ui.links.action.yml
+++ b/core/modules/field_ui/field_ui.links.action.yml
@@ -11,3 +11,7 @@ field_ui.entity_form_mode_add:
   weight: 1
   appears_on:
     - field_ui.entity_form_mode_list
+
+field_ui.field_storage_config_add:
+  class: \Drupal\Core\Menu\LocalActionDefault
+  deriver: \Drupal\field_ui\Plugin\Derivative\FieldUiLocalAction
diff --git a/core/modules/field_ui/src/Controller/FieldConfigListController.php b/core/modules/field_ui/src/Controller/FieldConfigListController.php
new file mode 100644
index 0000000..8ed9be0
--- /dev/null
+++ b/core/modules/field_ui/src/Controller/FieldConfigListController.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field_ui\Controller\FieldConfigListController.
+ */
+
+namespace Drupal\field_ui\Controller;
+
+use Drupal\Core\Entity\Controller\EntityListController;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines a controller to list field instances.
+ */
+class FieldConfigListController extends EntityListController {
+
+  /**
+   * Shows the 'Manage fields' page.
+   *
+   * @param string $entity_type_id
+   *   The entity type.
+   * @param string $bundle
+   *   The entity bundle.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return array
+   *   A render array as expected by drupal_render().
+   */
+  public function listing($entity_type_id = NULL, $bundle = NULL, Request $request = NULL) {
+    if (!$bundle) {
+      $entity_info = $this->entityManager()->getDefinition($entity_type_id);
+      $bundle = $request->attributes->get('_raw_variables')->get($entity_info->getBundleEntityType());
+    }
+    return $this->entityManager()->getListBuilder('field_config')->render($entity_type_id, $bundle, $request);
+  }
+
+}
diff --git a/core/modules/field_ui/src/DisplayOverviewBase.php b/core/modules/field_ui/src/DisplayOverviewBase.php
index adab34e..ebe217f 100644
--- a/core/modules/field_ui/src/DisplayOverviewBase.php
+++ b/core/modules/field_ui/src/DisplayOverviewBase.php
@@ -16,13 +16,50 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Field\PluginSettingsInterface;
+use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Field UI display overview base class.
  */
-abstract class DisplayOverviewBase extends OverviewBase {
+abstract class DisplayOverviewBase extends FormBase {
+
+  /**
+   * The name of the entity type.
+   *
+   * @var string
+   */
+  protected $entity_type = '';
+
+  /**
+   * The entity bundle.
+   *
+   * @var string
+   */
+  protected $bundle = '';
+
+  /**
+   * The entity type of the entity bundle.
+   *
+   * @var string
+   */
+  protected $bundleEntityType;
+
+  /**
+   * The entity view or form mode.
+   *
+   * @var string
+   */
+  protected $mode = '';
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
 
   /**
    * The display context. Either 'view' or 'form'.
@@ -65,8 +102,7 @@
    *   The configuration factory.
    */
   public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, PluginManagerBase $plugin_manager, ConfigFactoryInterface $config_factory) {
-    parent::__construct($entity_manager);
-
+    $this->entityManager = $entity_manager;
     $this->fieldTypes = $field_type_manager->getDefinitions();
     $this->pluginManager = $plugin_manager;
     $this->configFactory = $config_factory;
@@ -85,7 +121,23 @@ public static function create(ContainerInterface $container) {
   }
 
   /**
-   * {@inheritdoc}
+   * Get the regions needed to create the overview form.
+   *
+   * @return array
+   *   Example usage:
+   *   @code
+   *     return array(
+   *       'content' => array(
+   *         // label for the region.
+   *         'title' => $this->t('Content'),
+   *         // Indicates if the region is visible in the UI.
+   *         'invisible' => TRUE,
+   *         // A message to indicate that there is nothing to be displayed in
+   *         // the region.
+   *         'message' => $this->t('No field is displayed.'),
+   *       ),
+   *     );
+   *   @endcode
    */
   public function getRegions() {
     return array(
@@ -102,6 +154,20 @@ public function getRegions() {
   }
 
   /**
+   * Returns an associative array of all regions.
+   *
+   * @return array
+   *   An array containing the region options.
+   */
+  public function getRegionOptions() {
+    $options = array();
+    foreach ($this->getRegions() as $region => $data) {
+      $options[$region] = $data['title'];
+    }
+    return $options;
+  }
+
+  /**
    * Collects the definitions of fields whose display is configurable.
    *
    * @return \Drupal\Core\Field\FieldDefinitionInterface[]
@@ -118,8 +184,19 @@ protected function getFieldDefinitions() {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL, $mode = 'default') {
-    parent::buildForm($form, $form_state, $entity_type_id, $bundle);
+    $entity_type = $this->entityManager->getDefinition($entity_type_id);
+    $this->bundleEntityType = $entity_type->getBundleEntityType();
+    $stored_bundle = $form_state->get('bundle');
+    if (!$stored_bundle) {
+      if (!$bundle) {
+        $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($this->bundleEntityType);
+      }
+      $stored_bundle = $bundle;
+      $form_state->set('bundle', $bundle);
+    }
 
+    $this->entity_type = $entity_type_id;
+    $this->bundle = $stored_bundle;
     $this->mode = $mode;
 
     $field_definitions = $this->getFieldDefinitions();
@@ -690,6 +767,120 @@ public function multistepAjax($form, FormStateInterface $form_state) {
   }
 
   /**
+   * Performs pre-render tasks on field_ui_table elements.
+   *
+   * This function is assigned as a #pre_render callback in
+   * field_ui_element_info().
+   *
+   * @param array $elements
+   *   A structured array containing two sub-levels of elements. Properties
+   *   used:
+   *   - #tabledrag: The value is a list of $options arrays that are passed to
+   *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
+   *     $options array.
+   *
+   * @see drupal_render()
+   * @see \Drupal\Core\Render\Element\Table::preRenderTable()
+   */
+  public function tablePreRender($elements) {
+    $js_settings = array();
+
+    // For each region, build the tree structure from the weight and parenting
+    // data contained in the flat form structure, to determine row order and
+    // indentation.
+    $regions = $elements['#regions'];
+    $tree = array('' => array('name' => '', 'children' => array()));
+    $trees = array_fill_keys(array_keys($regions), $tree);
+
+    $parents = array();
+    $children = Element::children($elements);
+    $list = array_combine($children, $children);
+
+    // Iterate on rows until we can build a known tree path for all of them.
+    while ($list) {
+      foreach ($list as $name) {
+        $row = &$elements[$name];
+        $parent = $row['parent_wrapper']['parent']['#value'];
+        // Proceed if parent is known.
+        if (empty($parent) || isset($parents[$parent])) {
+          // Grab parent, and remove the row from the next iteration.
+          $parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array();
+          unset($list[$name]);
+
+          // Determine the region for the row.
+          $region_name = call_user_func($row['#region_callback'], $row);
+
+          // Add the element in the tree.
+          $target = &$trees[$region_name][''];
+          foreach ($parents[$name] as $key) {
+            $target = &$target['children'][$key];
+          }
+          $target['children'][$name] = array('name' => $name, 'weight' => $row['weight']['#value']);
+
+          // Add tabledrag indentation to the first row cell.
+          if ($depth = count($parents[$name])) {
+            $children = Element::children($row);
+            $cell = current($children);
+            $indentation = array(
+              '#theme' => 'indentation',
+              '#size' => $depth,
+            );
+            $row[$cell]['#prefix'] = drupal_render($indentation) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '');
+          }
+
+          // Add row id and associate JS settings.
+          $id = drupal_html_class($name);
+          $row['#attributes']['id'] = $id;
+          if (isset($row['#js_settings'])) {
+            $row['#js_settings'] += array(
+              'rowHandler' => $row['#row_type'],
+              'name' => $name,
+              'region' => $region_name,
+            );
+            $js_settings[$id] = $row['#js_settings'];
+          }
+        }
+      }
+    }
+    // Determine rendering order from the tree structure.
+    foreach ($regions as $region_name => $region) {
+      $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], array($this, 'reduceOrder'));
+    }
+
+    $elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings;
+
+    // If the custom #tabledrag is set and there is a HTML ID, add the table's
+    // HTML ID to the options and attach the behavior.
+    // @see \Drupal\Core\Render\Element\Table::preRenderTable()
+    if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
+      foreach ($elements['#tabledrag'] as $options) {
+        $options['table_id'] = $elements['#attributes']['id'];
+        drupal_attach_tabledrag($elements, $options);
+      }
+    }
+
+    return $elements;
+  }
+
+  /**
+   * Determines the rendering order of an array representing a tree.
+   *
+   * Callback for array_reduce() within
+   * \Drupal\field_ui\DisplayOverviewBase::tablePreRender().
+   */
+  public function reduceOrder($array, $a) {
+    $array = !isset($array) ? array() : $array;
+    if ($a['name']) {
+      $array[] = $a['name'];
+    }
+    if (!empty($a['children'])) {
+      uasort($a['children'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
+      $array = array_merge($array, array_reduce($a['children'], array($this, 'reduceOrder')));
+    }
+    return $array;
+  }
+
+  /**
    * Returns the entity display object used by this form.
    *
    * @param string $mode
diff --git a/core/modules/field_ui/src/FieldConfigListBuilder.php b/core/modules/field_ui/src/FieldConfigListBuilder.php
index cae4250..f0290ea 100644
--- a/core/modules/field_ui/src/FieldConfigListBuilder.php
+++ b/core/modules/field_ui/src/FieldConfigListBuilder.php
@@ -7,10 +7,15 @@
 
 namespace Drupal\field_ui;
 
+use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Url;
+use Drupal\field\FieldConfigInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -19,6 +24,34 @@
 class FieldConfigListBuilder extends ConfigEntityListBuilder {
 
   /**
+   * The name of the entity type the listed fields are attached to.
+   *
+   * @var string
+   */
+  protected $targetEntityTypeId;
+
+  /**
+   * The name of the bundle the listed fields are attached to.
+   *
+   * @var string
+   */
+  protected $targetBundle;
+
+  /**
+   * The entity type of the target entity bundle.
+   *
+   * @var string
+   */
+  protected $targetBundleEntityType;
+
+  /**
+   * An array of field type definitions.
+   *
+   * @var array
+   */
+  protected $fieldTypes;
+
+  /**
    * The entity manager.
    *
    * @var \Drupal\Core\Entity\EntityManagerInterface
@@ -32,27 +65,104 @@ class FieldConfigListBuilder extends ConfigEntityListBuilder {
    *   The entity type definition.
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
+   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
+   *   The field type manager
    */
-  public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager) {
+  public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
     parent::__construct($entity_type, $entity_manager->getStorage($entity_type->id()));
+
     $this->entityManager = $entity_manager;
+    $this->fieldTypeManager = $field_type_manager;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
-    return new static($entity_type, $container->get('entity.manager'));
+    return new static($entity_type, $container->get('entity.manager'), $container->get('plugin.manager.field.field_type'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render($target_entity_type_id = NULL, $target_bundle = NULL) {
+    $this->targetEntityTypeId = $target_entity_type_id;
+    $this->targetBundle = $target_bundle;
+    $this->targetBundleEntityType = $this->entityManager->getDefinition($target_entity_type_id)->getBundleEntityType();
+    $this->fieldTypes = $this->fieldTypeManager->getDefinitions();
+
+    $build = parent::render();
+    $build['#attributes']['id'] = 'field-overview';
+    $build['#empty'] = $this->t('No fields are present yet.');
+
+    return $build;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function render() {
-    // The actual field config overview is rendered by
-    // \Drupal\field_ui\FieldOverview, so we should not use this class to build
-    // lists.
-    throw new \Exception('This class is only used for operations and not for building lists.');
+  public function load() {
+    $entities = array_filter($this->entityManager->getFieldDefinitions($this->targetEntityTypeId, $this->targetBundle), function ($field_definition) {
+      return $field_definition instanceof FieldConfigInterface;
+    });
+
+    // Sort the entities using the entity class's sort() method.
+    // See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
+    uasort($entities, array($this->entityType->getClass(), 'sort'));
+    return $entities;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $header = array(
+      'label' => $this->t('Label'),
+      'field_name' => array(
+        'data' => $this->t('Machine name'),
+        'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
+      ),
+      'field_type' => $this->t('Field type'),
+    );
+    return $header + parent::buildHeader();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $field_config) {
+    /** @var \Drupal\field\FieldConfigInterface $field_config */
+    $field_storage = $field_config->getFieldStorageDefinition();
+    $route_parameters = array(
+      $this->targetBundleEntityType => $this->targetBundle,
+      'field_config' => $field_config->id(),
+    );
+
+    $row = array(
+      'id' => Html::getClass($field_config->getName()),
+      'data' => array(
+        'label' => String::checkPlain($field_config->getLabel()),
+        'field_name' => $field_config->getName(),
+        'field_type' => array(
+          'data' => array(
+            '#type' => 'link',
+            '#title' => $this->fieldTypes[$field_storage->getType()]['label'],
+            '#url' => Url::fromRoute('field_ui.storage_edit_' . $this->targetEntityTypeId, $route_parameters),
+            '#options' => array('attributes' => array('title' => $this->t('Edit field settings.'))),
+          ),
+        ),
+      ),
+    );
+
+    // Add the operations.
+    $row['data'] = $row['data'] + parent::buildRow($field_config);
+
+    if (!empty($field_storage->locked)) {
+      $row['data']['operations'] = array('data' => array('#markup' => $this->t('Locked')));
+      $row['class'][] = 'menu-disabled';
+    }
+
+    return $row;
   }
 
   /**
diff --git a/core/modules/field_ui/src/FieldOverview.php b/core/modules/field_ui/src/FieldOverview.php
deleted file mode 100644
index c780936..0000000
--- a/core/modules/field_ui/src/FieldOverview.php
+++ /dev/null
@@ -1,536 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\field_ui\FieldOverview.
- */
-
-namespace Drupal\field_ui;
-
-use Drupal\Component\Utility\String;
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Entity\EntityListBuilderInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Field\FieldTypePluginManagerInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Render\Element;
-use Drupal\Core\Url;
-use Drupal\field\FieldStorageConfigInterface;
-use Drupal\field_ui\OverviewBase;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\field\FieldConfigInterface;
-
-/**
- * Field UI field overview form.
- */
-class FieldOverview extends OverviewBase {
-
-  /**
-   *  The field type manager.
-   *
-   * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
-   */
-  protected $fieldTypeManager;
-
-  /**
-   * Constructs a new FieldOverview.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
-   *   The field type manager
-   */
-  public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct($entity_manager);
-    $this->fieldTypeManager = $field_type_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.manager'),
-      $container->get('plugin.manager.field.field_type')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRegions() {
-    return array(
-      'content' => array(
-        'title' => $this->t('Content'),
-        'invisible' => TRUE,
-        // @todo Bring back this message in https://drupal.org/node/1963340.
-        //'message' => $this->t('No fields are present yet.'),
-      ),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'field_ui_field_overview_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
-    parent::buildForm($form, $form_state, $entity_type_id, $bundle);
-
-    // Gather bundle information.
-    $fields = array_filter(\Drupal::entityManager()->getFieldDefinitions($this->entity_type, $this->bundle), function ($field_definition) {
-      return $field_definition instanceof FieldConfigInterface;
-    });
-    $field_types = $this->fieldTypeManager->getDefinitions();
-
-    // Field prefix.
-    $field_prefix = \Drupal::config('field_ui.settings')->get('field_prefix');
-
-    $form += array(
-      '#entity_type' => $this->entity_type,
-      '#bundle' => $this->bundle,
-      '#fields' => array_keys($fields),
-    );
-
-    $table = array(
-      '#type' => 'field_ui_table',
-      '#tree' => TRUE,
-      '#header' => array(
-        $this->t('Label'),
-        array(
-          'data' => $this->t('Machine name'),
-          'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
-        ),
-        $this->t('Field type'),
-        $this->t('Operations'),
-      ),
-      '#regions' => $this->getRegions(),
-      '#attributes' => array(
-        'class' => array('field-ui-overview'),
-        'id' => 'field-overview',
-      ),
-    );
-
-    // Fields.
-    foreach ($fields as $name => $field) {
-      $field_storage = $field->getFieldStorageDefinition();
-      $route_parameters = array(
-        $this->bundleEntityType => $this->bundle,
-        'field_config' => $field->id(),
-      );
-      $table[$name] = array(
-        '#attributes' => array(
-          'id' => drupal_html_class($name),
-        ),
-        'label' => array(
-          '#markup' => String::checkPlain($field->getLabel()),
-        ),
-        'field_name' => array(
-          '#markup' => $field->getName(),
-        ),
-        'type' => array(
-          '#type' => 'link',
-          '#title' => $field_types[$field_storage->getType()]['label'],
-          '#url' => Url::fromRoute('field_ui.storage_edit_' . $this->entity_type, $route_parameters),
-          '#options' => array('attributes' => array('title' => $this->t('Edit field settings.'))),
-        ),
-      );
-
-      $table[$name]['operations']['data'] = array(
-        '#type' => 'operations',
-        '#links' => $this->entityManager->getListBuilder('field_config')->getOperations($field),
-      );
-
-      if (!empty($field_storage->locked)) {
-        $table[$name]['operations'] = array('#markup' => $this->t('Locked'));
-        $table[$name]['#attributes']['class'][] = 'menu-disabled';
-      }
-    }
-
-    // Gather valid field types.
-    $field_type_options = array();
-    foreach ($field_types as $name => $field_type) {
-      // Skip field types which should not be added via user interface.
-      if (empty($field_type['no_ui'])) {
-        $field_type_options[$name] = $field_type['label'];
-      }
-    }
-    asort($field_type_options);
-
-    // Additional row: add new field.
-    if ($field_type_options) {
-      $name = '_add_new_field';
-      $table[$name] = array(
-        '#attributes' => array('class' => array('add-new')),
-        'label' => array(
-          '#type' => 'textfield',
-          '#title' => $this->t('New field label'),
-          '#title_display' => 'invisible',
-          '#size' => 15,
-          '#description' => $this->t('Label'),
-          '#prefix' => '<div class="label-input"><div class="add-new-placeholder">' . $this->t('Add new field') .'</div>',
-          '#suffix' => '</div>',
-        ),
-        'field_name' => array(
-          '#type' => 'machine_name',
-          '#title' => $this->t('New field name'),
-          '#title_display' => 'invisible',
-          // This field should stay LTR even for RTL languages.
-          '#field_prefix' => '<span dir="ltr">' . $field_prefix,
-          '#field_suffix' => '</span>&lrm;',
-          '#size' => 15,
-          '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'),
-          // Calculate characters depending on the length of the field prefix
-          // setting. Maximum length is 32.
-          '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix),
-          '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
-          '#machine_name' => array(
-            'source' => array('fields', $name, 'label'),
-            'exists' => array($this, 'fieldNameExists'),
-            'standalone' => TRUE,
-            'label' => '',
-          ),
-          '#required' => FALSE,
-        ),
-        'type' => array(
-          '#type' => 'select',
-          '#title' => $this->t('Type of new field'),
-          '#title_display' => 'invisible',
-          '#options' => $field_type_options,
-          '#empty_option' => $this->t('- Select a field type -'),
-          '#description' => $this->t('Type of data to store.'),
-          '#attributes' => array('class' => array('field-type-select')),
-          '#cell_attributes' => array('colspan' => 2),
-          '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
-        ),
-        // Place the 'translatable' property as an explicit value so that
-        // contrib modules can form_alter() the value for newly created fields.
-        'translatable' => array(
-          '#type' => 'value',
-          '#value' => TRUE,
-        ),
-      );
-    }
-
-    // Additional row: re-use existing field storages.
-    $existing_fields = $this->getExistingFieldStorageOptions();
-    if ($existing_fields) {
-      // Build list of options.
-      $existing_field_options = array();
-      foreach ($existing_fields as $field_name => $info) {
-        $text = $this->t('@type: @field', array(
-          '@type' => $info['type_label'],
-          '@field' => $info['field'],
-        ));
-        $existing_field_options[$field_name] = Unicode::truncate($text, 80, FALSE, TRUE);
-      }
-      asort($existing_field_options);
-      $name = '_add_existing_field';
-      $table[$name] = array(
-        '#attributes' => array('class' => array('add-new')),
-        '#row_type' => 'add_new_field',
-        '#region_callback' => array($this, 'getRowRegion'),
-        'label' => array(
-          '#type' => 'textfield',
-          '#title' => $this->t('Existing field label'),
-          '#title_display' => 'invisible',
-          '#size' => 15,
-          '#description' => $this->t('Label'),
-          '#attributes' => array('class' => array('label-textfield')),
-          '#prefix' => '<div class="label-input"><div class="add-new-placeholder">' . $this->t('Re-use existing field') .'</div>',
-          '#suffix' => '</div>',
-        ),
-        'field_name' => array(
-          '#type' => 'select',
-          '#title' => $this->t('Existing field to share'),
-          '#title_display' => 'invisible',
-          '#options' => $existing_field_options,
-          '#empty_option' => $this->t('- Select an existing field -'),
-          '#description' => $this->t('Field to share'),
-          '#attributes' => array('class' => array('field-select')),
-          '#cell_attributes' => array('colspan' => 3),
-          '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
-        ),
-      );
-    }
-
-    // We can set the 'rows_order' element, needed by theme_field_ui_table(),
-    // here instead of a #pre_render callback because this form doesn't have the
-    // tabledrag behavior anymore.
-    $table['#regions']['content']['rows_order'] = array();
-    foreach (Element::children($table) as $name) {
-      $table['#regions']['content']['rows_order'][] = $name;
-    }
-
-    $form['fields'] = $table;
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
-      '#type' => 'submit',
-      '#button_type' => 'primary',
-      '#value' => $this->t('Save'));
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    $this->validateAddNew($form, $form_state);
-    $this->validateAddExisting($form, $form_state);
-  }
-
-  /**
-   * Validates the 'add new field' row.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The current state of the form.
-   *
-   * @see \Drupal\field_ui\FieldOverview::validateForm()
-   */
-  protected function validateAddNew(array $form, FormStateInterface $form_state) {
-    $field = $form_state->getValue(array('fields', '_add_new_field'));
-
-    // Validate if any information was provided in the 'add new field' row.
-    if (array_filter(array($field['label'], $field['field_name'], $field['type']))) {
-      // Missing label.
-      if (!$field['label']) {
-        $form_state->setErrorByName('fields][_add_new_field][label', $this->t('Add new field: you need to provide a label.'));
-      }
-
-      // Missing field name.
-      if (!$field['field_name']) {
-        $form_state->setErrorByName('fields][_add_new_field][field_name', $this->t('Add new field: you need to provide a machine name for the field.'));
-      }
-      // Field name validation.
-      else {
-        $field_name = $field['field_name'];
-
-        // Add the field prefix.
-        $field_name = \Drupal::config('field_ui.settings')->get('field_prefix') . $field_name;
-        $form_state->setValueForElement($form['fields']['_add_new_field']['field_name'], $field_name);
-      }
-
-      // Missing field type.
-      if (!$field['type']) {
-        $form_state->setErrorByName('fields][_add_new_field][type', $this->t('Add new field: you need to select a field type.'));
-      }
-    }
-  }
-
-  /**
-   * Validates the 're-use existing field' row.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The current state of the form.
-   *
-   * @see \Drupal\field_ui\FieldOverview::validate()
-   */
-  protected function validateAddExisting(array $form, FormStateInterface $form_state) {
-    // The form element might be absent if no existing fields can be added to
-    // this bundle.
-    if ($field = $form_state->getValue(array('fields', '_add_existing_field'))) {
-      // Validate if any information was provided in the
-      // 're-use existing field' row.
-      if (array_filter(array($field['label'], $field['field_name']))) {
-        // Missing label.
-        if (!$field['label']) {
-          $form_state->setErrorByName('fields][_add_existing_field][label', $this->t('Re-use existing field: you need to provide a label.'));
-        }
-
-        // Missing existing field name.
-        if (!$field['field_name']) {
-          $form_state->setErrorByName('fields][_add_existing_field][field_name', $this->t('Re-use existing field: you need to select a field.'));
-        }
-      }
-    }
-  }
-
-  /**
-   * Overrides \Drupal\field_ui\OverviewBase::submitForm().
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $error = FALSE;
-    $form_values = $form_state->getValue('fields');
-    $destinations = array();
-
-    // Create new field.
-    if (!empty($form_values['_add_new_field']['field_name'])) {
-      $values = $form_values['_add_new_field'];
-
-      $field_storage = array(
-        'field_name' => $values['field_name'],
-        'entity_type' => $this->entity_type,
-        'type' => $values['type'],
-        'translatable' => $values['translatable'],
-      );
-      $field = array(
-        'field_name' => $values['field_name'],
-        'entity_type' => $this->entity_type,
-        'bundle' => $this->bundle,
-        'label' => $values['label'],
-        // Field translatability should be explicitly enabled by the users.
-        'translatable' => FALSE,
-      );
-
-      // Create the field storage and field.
-      try {
-        $this->entityManager->getStorage('field_storage_config')->create($field_storage)->save();
-        $new_field = $this->entityManager->getStorage('field_config')->create($field);
-        $new_field->save();
-
-        // Make sure the field is displayed in the 'default' form mode (using
-        // default widget and settings). It stays hidden for other form modes
-        // until it is explicitly configured.
-        entity_get_form_display($this->entity_type, $this->bundle, 'default')
-          ->setComponent($values['field_name'])
-          ->save();
-
-        // Make sure the field is displayed in the 'default' view mode (using
-        // default formatter and settings). It stays hidden for other view
-        // modes until it is explicitly configured.
-        entity_get_display($this->entity_type, $this->bundle, 'default')
-          ->setComponent($values['field_name'])
-          ->save();
-
-        // Always show the field settings step, as the cardinality needs to be
-        // configured for new fields.
-        $route_parameters = array(
-          $this->bundleEntityType => $this->bundle,
-          'field_config' => $new_field->id(),
-        );
-        $destinations[] = array('route_name' => 'field_ui.storage_edit_' . $this->entity_type, 'route_parameters' => $route_parameters);
-        $destinations[] = array('route_name' => 'field_ui.field_edit_' . $this->entity_type, 'route_parameters' => $route_parameters);
-
-        // Store new field information for any additional submit handlers.
-        $form_state->set(['fields_added', '_add_new_field'], $values['field_name']);
-      }
-      catch (\Exception $e) {
-        $error = TRUE;
-        drupal_set_message($this->t('There was a problem creating field %label: !message', array('%label' => $field['label'], '!message' => $e->getMessage())), 'error');
-      }
-    }
-
-    // Re-use existing field.
-    if (!empty($form_values['_add_existing_field']['field_name'])) {
-      $values = $form_values['_add_existing_field'];
-      $field_name = $values['field_name'];
-      $field_storage = FieldStorageConfig::loadByName($this->entity_type, $field_name);
-      if (!empty($field_storage->locked)) {
-        drupal_set_message($this->t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error');
-      }
-      else {
-        $field = array(
-          'field_name' => $field_name,
-          'entity_type' => $this->entity_type,
-          'bundle' => $this->bundle,
-          'label' => $values['label'],
-        );
-
-        try {
-          $new_field = $this->entityManager->getStorage('field_config')->create($field);
-          $new_field->save();
-
-          // Make sure the field is displayed in the 'default' form mode (using
-          // default widget and settings). It stays hidden for other form modes
-          // until it is explicitly configured.
-          entity_get_form_display($this->entity_type, $this->bundle, 'default')
-            ->setComponent($field_name)
-            ->save();
-
-          // Make sure the field is displayed in the 'default' view mode (using
-          // default formatter and settings). It stays hidden for other view
-          // modes until it is explicitly configured.
-          entity_get_display($this->entity_type, $this->bundle, 'default')
-            ->setComponent($field_name)
-            ->save();
-
-          $destinations[] = array(
-            'route_name' => 'field_ui.field_edit_' . $this->entity_type,
-            'route_parameters' => array(
-              $this->bundleEntityType => $this->bundle,
-              'field_config' => $new_field->id(),
-            ),
-          );
-          // Store new field information for any additional submit handlers.
-          $form_state->set(['fields_added', '_add_existing_field'], $field['field_name']);
-        }
-        catch (\Exception $e) {
-          $error = TRUE;
-          drupal_set_message($this->t('There was a problem creating field %label: @message.', array('%label' => $field['label'], '@message' => $e->getMessage())), 'error');
-        }
-      }
-    }
-
-    if ($destinations) {
-      $destination = drupal_get_destination();
-      $destinations[] = $destination['destination'];
-      $form_state->setRedirectUrl(FieldUI::getNextDestination($destinations, $form_state));
-    }
-    elseif (!$error) {
-      drupal_set_message($this->t('Your settings have been saved.'));
-    }
-  }
-
-  /**
-   * Returns an array of existing field storages that can be added to a bundle.
-   *
-   * @return array
-   *   An array of existing field storages keyed by name.
-   */
-  protected function getExistingFieldStorageOptions() {
-    $options = array();
-    // Load the field_storages and build the list of options.
-    $field_types = $this->fieldTypeManager->getDefinitions();
-    foreach ($this->entityManager->getFieldStorageDefinitions($this->entity_type) as $field_name => $field_storage) {
-      // Do not show:
-      // - non-configurable field storages,
-      // - locked field_storages,
-      // - field_storages that should not be added via user interface,
-      // - field_storages that already have a field in the bundle.
-      $field_type = $field_storage->getType();
-      if ($field_storage instanceof FieldStorageConfigInterface
-        && !$field_storage->isLocked()
-        && empty($field_types[$field_type]['no_ui'])
-        && !in_array($this->bundle, $field_storage->getBundles(), TRUE)) {
-        $options[$field_name] = array(
-          'type' => $field_type,
-          'type_label' => $field_types[$field_type]['label'],
-          'field' => $field_name,
-        );
-      }
-    }
-
-    return $options;
-  }
-
-  /**
-   * Checks if a field machine name is taken.
-   *
-   * @param string $value
-   *   The machine name, not prefixed.
-   *
-   * @return bool
-   *   Whether or not the field machine name is taken.
-   */
-  public function fieldNameExists($value) {
-    // Add the field prefix.
-    $field_name = \Drupal::config('field_ui.settings')->get('field_prefix') . $value;
-
-    $field_storage_definitions = \Drupal::entityManager()->getFieldStorageDefinitions($this->entity_type);
-    return isset($field_storage_definitions[$field_name]);
-  }
-
-}
diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
new file mode 100644
index 0000000..891413f
--- /dev/null
+++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
@@ -0,0 +1,473 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field_ui\Form\FieldStorageAddForm.
+ */
+
+namespace Drupal\field_ui\Form;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\field\FieldStorageConfigInterface;
+use Drupal\field_ui\FieldUI;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a form for the "field storage" add page.
+ */
+class FieldStorageAddForm extends FormBase {
+
+  /**
+   * The name of the entity type.
+   *
+   * @var string
+   */
+  protected $entityTypeId;
+
+  /**
+   * The entity bundle.
+   *
+   * @var string
+   */
+  protected $bundle;
+
+  /**
+   * The entity type of the entity bundle.
+   *
+   * @var string
+   */
+  protected $bundleEntityTypeId;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * The field type plugin manager.
+   *
+   * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
+   */
+  protected $fieldTypePluginManager;
+
+  /**
+   * Constructs a new FieldStorageAddForm object.
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_plugin_manager
+   *   The field type plugin manager.
+   */
+  public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_plugin_manager) {
+    $this->entityManager = $entity_manager;
+    $this->fieldTypePluginManager = $field_type_plugin_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'field_ui_field_storage_add_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity.manager'),
+      $container->get('plugin.manager.field.field_type')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
+    $entity_type = $this->entityManager->getDefinition($entity_type_id);
+    $this->bundleEntityTypeId = $entity_type->getBundleEntityType();
+    if (!$form_state->hasValue('bundle')) {
+      if (!$bundle) {
+        $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($this->bundleEntityTypeId);
+      }
+      $form_state->setValue('bundle', $bundle);
+    }
+
+    $this->entityTypeId = $entity_type_id;
+    $this->bundle = $form_state->getValue('bundle');
+
+    $form += array(
+      '#entity_type_id' => $this->entityTypeId,
+      '#bundle' => $this->bundle,
+    );
+
+    // Gather valid field types.
+    $field_type_options = array();
+    foreach ($this->fieldTypePluginManager->getDefinitions() as $name => $field_type) {
+      // Skip field types which should not be added via user interface.
+      if (empty($field_type['no_ui'])) {
+        $field_type_options[$name] = $field_type['label'];
+      }
+    }
+    asort($field_type_options);
+
+    $form['field'] = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('field-type-wrapper', 'clearfix')),
+    );
+
+    $form['field']['type'] = array(
+      '#type' => 'select',
+      '#title' => $this->t('Add a new field'),
+      '#options' => $field_type_options,
+      '#empty_option' => $this->t('- Select a field type -'),
+    );
+
+    // Re-use existing field.
+    if ($existing_fields = $this->getExistingFieldStorageOptions()) {
+      // Build list of options.
+      $existing_field_options = array();
+      foreach ($existing_fields as $field_name => $info) {
+        $text = $this->t('@type: @field', array(
+          '@type' => $info['type_label'],
+          '@field' => $info['field'],
+        ));
+        $existing_field_options[$field_name] = Unicode::truncate($text, 80, FALSE, TRUE);
+      }
+      asort($existing_field_options);
+
+      $form['field']['separator'] = array(
+        '#type' => 'item',
+        '#markup' => $this->t('or'),
+      );
+      $form['field']['existing_field_name'] = array(
+        '#type' => 'select',
+        '#title' => $this->t('Re-use an existing field'),
+        '#options' => $existing_field_options,
+        '#empty_option' => $this->t('- Select an existing field -'),
+      );
+    }
+    else {
+      // Provide a placeholder form element to simply the validation code.
+      $form['field']['existing_field_name'] = array(
+        '#type' => 'value',
+        '#value' => FALSE,
+      );
+    }
+
+    $form['new_field_wrapper'] = array(
+      '#type' => 'container',
+      '#states' => array(
+        '!visible' => array(
+          ':input[name="type"]' => array('value' => ''),
+        ),
+      ),
+    );
+    $form['new_field_wrapper']['label'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Label'),
+      '#size' => 15,
+    );
+
+    $field_prefix = $this->config('field_ui.settings')->get('field_prefix');
+    $form['new_field_wrapper']['field_name'] = array(
+      '#type' => 'machine_name',
+      // This field should stay LTR even for RTL languages.
+      '#field_prefix' => '<span dir="ltr">' . $field_prefix,
+      '#field_suffix' => '</span>&lrm;',
+      '#size' => 15,
+      '#description' => $this->t('A unique machine-readable name containing letters, numbers, and underscores.'),
+      // Calculate characters depending on the length of the field prefix
+      // setting. Maximum length is 32.
+      '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix),
+      '#machine_name' => array(
+        'source' => array('new_field_wrapper', 'label'),
+        'exists' => array($this, 'fieldNameExists'),
+      ),
+      '#required' => FALSE,
+    );
+
+    // Place the 'translatable' property as an explicit value so that
+    // contrib modules can form_alter() the value for newly created fields.
+    $form['translatable'] = array(
+      '#type' => 'value',
+      '#value' => FALSE,
+    );
+
+    $form['actions'] = array('#type' => 'actions');
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => $this->t('Save and continue'),
+      '#button_type' => 'primary',
+    );
+
+    $form['#attached']['library'][] = 'field_ui/drupal.field_ui';
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    // Missing field type.
+    if (!$form_state->getValue('type') && !$form_state->getValue('existing_field_name')) {
+      $form_state->setErrorByName('type', $this->t('You need to select a field type.'));
+    }
+    // Both field type and existing field option selected. This is prevented in
+    // the UI with JavaScript but we also need a proper server-side validation.
+    elseif ($form_state->getValue('type') && $form_state->getValue('existing_field_name')) {
+      $form_state->setErrorByName('type', $this->t('Adding a new field and re-using an existing field at the same time is not allowed.'));
+      return;
+    }
+
+    $this->validateAddNew($form, $form_state);
+    $this->validateAddExisting($form, $form_state);
+  }
+
+  /**
+   * Validates the 'add new field' case.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @see \Drupal\field_ui\Form\FieldStorageAddForm::validateForm()
+   */
+  protected function validateAddNew(array $form, FormStateInterface $form_state) {
+    $field = $form_state->getValues();
+
+    // Validate if any information was provided in the 'add new field' case.
+    if (!$field['existing_field_name'] && array_filter(array($field['label'], $field['field_name'], $field['type']))) {
+      // Missing label.
+      if (!$field['label']) {
+        $form_state->setErrorByName('label', $this->t('Add new field: you need to provide a label.'));
+      }
+
+      // Missing field name.
+      if (!$field['field_name']) {
+        $form_state->setErrorByName('field_name', $this->t('Add new field: you need to provide a machine name for the field.'));
+      }
+      // Field name validation.
+      else {
+        $field_name = $field['field_name'];
+
+        // Add the field prefix.
+        $field_name = \Drupal::config('field_ui.settings')->get('field_prefix') . $field_name;
+        $form_state->setValueForElement($form['new_field_wrapper']['field_name'], $field_name);
+      }
+    }
+  }
+
+  /**
+   * Validates the 're-use existing field' case.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @see \Drupal\field_ui\Form\FieldStorageAddForm::validateForm()
+   */
+  protected function validateAddExisting(array $form, FormStateInterface $form_state) {
+    // The form element might be absent if no existing fields can be added to
+    // this bundle.
+    if ($form_state->getValue('existing_field_name')) {
+      // Discard any values that might be set for the 'label' and 'field_name'
+      // form elements.
+      $form_state->setValueForElement($form['new_field_wrapper']['label'], '');
+      $form_state->setValueForElement($form['new_field_wrapper']['field_name'], '');
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $error = FALSE;
+    $values = $form_state->getValues();
+    $destinations = array();
+
+    // Create new field.
+    if ($values['type']) {
+      $field_storage = array(
+        'field_name' => $values['field_name'],
+        'entity_type' => $this->entityTypeId,
+        'type' => $values['type'],
+        'translatable' => $values['translatable'],
+      );
+      $field = array(
+        'field_name' => $values['field_name'],
+        'entity_type' => $this->entityTypeId,
+        'bundle' => $this->bundle,
+        'label' => $values['label'],
+        // Field translatability should be explicitly enabled by the users.
+        'translatable' => FALSE,
+      );
+
+      // Create the field storage and field.
+      try {
+        $this->entityManager->getStorage('field_storage_config')->create($field_storage)->save();
+        $new_field = $this->entityManager->getStorage('field_config')->create($field);
+        $new_field->save();
+
+        $this->configureEntityDisplays($values['field_name']);
+
+        // Always show the field settings step, as the cardinality needs to be
+        // configured for new fields.
+        $route_parameters = array(
+          $this->bundleEntityTypeId => $this->bundle,
+          'field_config' => $new_field->id(),
+        );
+        $destinations[] = array('route_name' => 'field_ui.storage_edit_' . $this->entityTypeId, 'route_parameters' => $route_parameters);
+        $destinations[] = array('route_name' => 'field_ui.field_edit_' . $this->entityTypeId, 'route_parameters' => $route_parameters);
+        $destinations[] = array('route_name' => 'field_ui.overview_' . $this->entityTypeId, 'route_parameters' => $route_parameters);
+
+        // Store new field information for any additional submit handlers.
+        $form_state->set(['fields_added', '_add_new_field'], $values['field_name']);
+      }
+      catch (\Exception $e) {
+        $error = TRUE;
+        drupal_set_message($this->t('There was a problem creating field %label: !message', array('%label' => $field['label'], '!message' => $e->getMessage())), 'error');
+      }
+    }
+
+    // Re-use existing field.
+    if (!empty($values['existing_field_name'])) {
+      $field_name = $values['existing_field_name'];
+      $field_storage = FieldStorageConfig::loadByName($this->entityTypeId, $field_name);
+      if ($field_storage->isLocked()) {
+        drupal_set_message($this->t('The field %field_name cannot be added because it is locked.', array('%field_name' => $field_storage->getName())), 'error');
+      }
+      else {
+        $field = array(
+          'field_name' => $field_name,
+          'entity_type' => $this->entityTypeId,
+          'bundle' => $this->bundle,
+          // @todo Should we try to populate this value on a best-effort basis?
+          // (i.e. use the label of the first instance of this field storage)
+          'label' => '',
+        );
+
+        try {
+          $new_field = $this->entityManager->getStorage('field_config')->create($field);
+          $new_field->save();
+
+          $this->configureEntityDisplays($field_name);
+
+          $route_parameters = array(
+            $this->bundleEntityTypeId => $this->bundle,
+            'field_config' => $new_field->id(),
+          );
+          $destinations[] = array('route_name' => 'field_ui.field_edit_' . $this->entityTypeId, 'route_parameters' => $route_parameters);
+          $destinations[] = array('route_name' => 'field_ui.overview_' . $this->entityTypeId, 'route_parameters' => $route_parameters);
+
+          // Store new field information for any additional submit handlers.
+          $form_state->set(['fields_added', '_add_existing_field'], $field['field_name']);
+        }
+        catch (\Exception $e) {
+          $error = TRUE;
+          drupal_set_message($this->t('There was a problem creating field %field_name: @message.', array('%field_name' => $field_storage->getName(), '@message' => $e->getMessage())), 'error');
+        }
+      }
+    }
+
+    if ($destinations) {
+      $destination = drupal_get_destination();
+      $destinations[] = $destination['destination'];
+      $form_state->setRedirectUrl(FieldUI::getNextDestination($destinations, $form_state));
+    }
+    elseif (!$error) {
+      drupal_set_message($this->t('Your settings have been saved.'));
+    }
+  }
+
+  /**
+   * Configures the newly created field for the default view and form modes.
+   *
+   * @param string $field_name
+   *   The field name.
+   */
+  protected function configureEntityDisplays($field_name) {
+    // Make sure the field is displayed in the 'default' form mode (using
+    // default widget and settings). It stays hidden for other form modes
+    // until it is explicitly configured.
+    entity_get_form_display($this->entityTypeId, $this->bundle, 'default')
+      ->setComponent($field_name)
+      ->save();
+
+    // Make sure the field is displayed in the 'default' view mode (using
+    // default formatter and settings). It stays hidden for other view
+    // modes until it is explicitly configured.
+    entity_get_display($this->entityTypeId, $this->bundle, 'default')
+      ->setComponent($field_name)
+      ->save();
+  }
+
+  /**
+   * Returns an array of existing field storages that can be added to a bundle.
+   *
+   * @return array
+   *   An array of existing field storages keyed by name.
+   */
+  protected function getExistingFieldStorageOptions() {
+    $options = array();
+    // Load the field_storages and build the list of options.
+    $field_types = $this->fieldTypePluginManager->getDefinitions();
+    foreach ($this->entityManager->getFieldStorageDefinitions($this->entityTypeId) as $field_name => $field_storage) {
+      // Do not show:
+      // - non-configurable field storages,
+      // - locked field_storages,
+      // - field_storages that should not be added via user interface,
+      // - field_storages that already have a field in the bundle.
+      $field_type = $field_storage->getType();
+      if ($field_storage instanceof FieldStorageConfigInterface
+        && !$field_storage->isLocked()
+        && empty($field_types[$field_type]['no_ui'])
+        && !in_array($this->bundle, $field_storage->getBundles(), TRUE)) {
+        $options[$field_name] = array(
+          'type' => $field_type,
+          'type_label' => $field_types[$field_type]['label'],
+          'field' => $field_name,
+        );
+      }
+    }
+
+    return $options;
+  }
+
+  /**
+   * Checks if a field machine name is taken.
+   *
+   * @param string $value
+   *   The machine name, not prefixed.
+   * @param array $element
+   *   An array containing the structure of the 'field_name' element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @return bool
+   *   Whether or not the field machine name is taken.
+   */
+  public function fieldNameExists($value, $element, FormStateInterface $form_state) {
+    // Don't validate the case when an existing field has been selected.
+    if ($form_state->getValue('existing_field_name')) {
+      return FALSE;
+    }
+
+    // Add the field prefix.
+    $field_name = \Drupal::config('field_ui.settings')->get('field_prefix') . $value;
+
+    $field_storage_definitions = \Drupal::entityManager()->getFieldStorageDefinitions($this->entityTypeId);
+    return isset($field_storage_definitions[$field_name]);
+  }
+
+}
diff --git a/core/modules/field_ui/src/OverviewBase.php b/core/modules/field_ui/src/OverviewBase.php
deleted file mode 100644
index 93adaa8..0000000
--- a/core/modules/field_ui/src/OverviewBase.php
+++ /dev/null
@@ -1,246 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\field_ui\OverviewBase.
- */
-
-namespace Drupal\field_ui;
-
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Render\Element;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Abstract base class for Field UI overview forms.
- */
-abstract class OverviewBase extends FormBase {
-
-  /**
-   * The name of the entity type.
-   *
-   * @var string
-   */
-  protected $entity_type = '';
-
-  /**
-   * The entity bundle.
-   *
-   * @var string
-   */
-  protected $bundle = '';
-
-  /**
-   * The entity type of the entity bundle.
-   *
-   * @var string
-   */
-  protected $bundleEntityType;
-
-  /**
-   * The entity view or form mode.
-   *
-   * @var string
-   */
-  protected $mode = '';
-
-  /**
-   * The entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
-   */
-  protected $entityManager;
-
-  /**
-   * Constructs a new OverviewBase.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
-   */
-  public function __construct(EntityManagerInterface $entity_manager) {
-    $this->entityManager = $entity_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.manager')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
-    $entity_type = $this->entityManager->getDefinition($entity_type_id);
-    $this->bundleEntityType = $entity_type->getBundleEntityType();
-    $stored_bundle = $form_state->get('bundle');
-    if (!$stored_bundle) {
-      if (!$bundle) {
-        $bundle = $this->getRequest()->attributes->get('_raw_variables')->get($this->bundleEntityType);
-      }
-      $stored_bundle = $bundle;
-      $form_state->set('bundle', $bundle);
-    }
-
-    $this->entity_type = $entity_type_id;
-    $this->bundle = $stored_bundle;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-  }
-
-  /**
-   * Get the regions needed to create the overview form.
-   *
-   * @return array
-   *   Example usage:
-   *   @code
-   *     return array(
-   *       'content' => array(
-   *         // label for the region.
-   *         'title' => $this->t('Content'),
-   *         // Indicates if the region is visible in the UI.
-   *         'invisible' => TRUE,
-   *         // A message to indicate that there is nothing to be displayed in
-   *         // the region.
-   *         'message' => $this->t('No field is displayed.'),
-   *       ),
-   *     );
-   *   @endcode
-   */
-  abstract public function getRegions();
-
-  /**
-   * Returns an associative array of all regions.
-   */
-  public function getRegionOptions() {
-    $options = array();
-    foreach ($this->getRegions() as $region => $data) {
-      $options[$region] = $data['title'];
-    }
-    return $options;
-  }
-
-  /**
-   * Performs pre-render tasks on field_ui_table elements.
-   *
-   * This function is assigned as a #pre_render callback in
-   * field_ui_element_info().
-   *
-   * @param array $element
-   *   A structured array containing two sub-levels of elements. Properties
-   *   used:
-   *   - #tabledrag: The value is a list of $options arrays that are passed to
-   *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
-   *     $options array.
-   *
-   * @see drupal_render()
-   * @see \Drupal\Core\Render\Element\Table::preRenderTable()
-   */
-  public function tablePreRender($elements) {
-    $js_settings = array();
-
-    // For each region, build the tree structure from the weight and parenting
-    // data contained in the flat form structure, to determine row order and
-    // indentation.
-    $regions = $elements['#regions'];
-    $tree = array('' => array('name' => '', 'children' => array()));
-    $trees = array_fill_keys(array_keys($regions), $tree);
-
-    $parents = array();
-    $children = Element::children($elements);
-    $list = array_combine($children, $children);
-
-    // Iterate on rows until we can build a known tree path for all of them.
-    while ($list) {
-      foreach ($list as $name) {
-        $row = &$elements[$name];
-        $parent = $row['parent_wrapper']['parent']['#value'];
-        // Proceed if parent is known.
-        if (empty($parent) || isset($parents[$parent])) {
-          // Grab parent, and remove the row from the next iteration.
-          $parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array();
-          unset($list[$name]);
-
-          // Determine the region for the row.
-          $region_name = call_user_func($row['#region_callback'], $row);
-
-          // Add the element in the tree.
-          $target = &$trees[$region_name][''];
-          foreach ($parents[$name] as $key) {
-            $target = &$target['children'][$key];
-          }
-          $target['children'][$name] = array('name' => $name, 'weight' => $row['weight']['#value']);
-
-          // Add tabledrag indentation to the first row cell.
-          if ($depth = count($parents[$name])) {
-            $children = Element::children($row);
-            $cell = current($children);
-            $indentation = array(
-              '#theme' => 'indentation',
-              '#size' => $depth,
-            );
-            $row[$cell]['#prefix'] = drupal_render($indentation) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '');
-          }
-
-          // Add row id and associate JS settings.
-          $id = drupal_html_class($name);
-          $row['#attributes']['id'] = $id;
-          if (isset($row['#js_settings'])) {
-            $row['#js_settings'] += array(
-              'rowHandler' => $row['#row_type'],
-              'name' => $name,
-              'region' => $region_name,
-            );
-            $js_settings[$id] = $row['#js_settings'];
-          }
-        }
-      }
-    }
-    // Determine rendering order from the tree structure.
-    foreach ($regions as $region_name => $region) {
-      $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], array($this, 'reduceOrder'));
-    }
-
-    $elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings;
-
-    // If the custom #tabledrag is set and there is a HTML ID, add the table's
-    // HTML ID to the options and attach the behavior.
-    // @see \Drupal\Core\Render\Element\Table::preRenderTable()
-    if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
-      foreach ($elements['#tabledrag'] as $options) {
-        $options['table_id'] = $elements['#attributes']['id'];
-        drupal_attach_tabledrag($elements, $options);
-      }
-    }
-
-    return $elements;
-  }
-
-  /**
-   * Determines the rendering order of an array representing a tree.
-   *
-   * Callback for array_reduce() within
-   * \Drupal\field_ui\OverviewBase::tablePreRender().
-   */
-  public function reduceOrder($array, $a) {
-    $array = !isset($array) ? array() : $array;
-    if ($a['name']) {
-      $array[] = $a['name'];
-    }
-    if (!empty($a['children'])) {
-      uasort($a['children'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
-      $array = array_merge($array, array_reduce($a['children'], array($this, 'reduceOrder')));
-    }
-    return $array;
-  }
-
-}
diff --git a/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalAction.php b/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalAction.php
new file mode 100644
index 0000000..88b47e8
--- /dev/null
+++ b/core/modules/field_ui/src/Plugin/Derivative/FieldUiLocalAction.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @fie
+ * Contains \Drupal\field_ui\Plugin\Derivative\FieldUiLocalAction.
+ */
+
+namespace Drupal\field_ui\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\Routing\RouteProviderInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides local action definitions for all entity bundles.
+ */
+class FieldUiLocalAction extends DeriverBase implements ContainerDeriverInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The entity manager
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a FieldUiLocalAction object.
+   *
+   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
+   *   The route provider to load routes by name.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(RouteProviderInterface $route_provider, EntityManagerInterface $entity_manager) {
+    $this->routeProvider = $route_provider;
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('router.route_provider'),
+      $container->get('entity.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $this->derivatives = array();
+
+    foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
+      if ($entity_type->get('field_ui_base_route')) {
+        $this->derivatives["field_storage_config_add_$entity_type_id"] = array(
+          'route_name' => "field_ui.field_storage_config_add_$entity_type_id",
+          'title' => $this->t('Add field'),
+          'appears_on' => array("field_ui.overview_$entity_type_id"),
+        );
+      }
+    }
+
+    foreach ($this->derivatives as &$entry) {
+      $entry += $base_plugin_definition;
+    }
+
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/modules/field_ui/src/Routing/RouteSubscriber.php b/core/modules/field_ui/src/Routing/RouteSubscriber.php
index 3abb6cf..51fa63b 100644
--- a/core/modules/field_ui/src/Routing/RouteSubscriber.php
+++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php
@@ -90,7 +90,7 @@ protected function alterRoutes(RouteCollection $collection) {
         $route = new Route(
           "$path/fields",
           array(
-            '_form' => '\Drupal\field_ui\FieldOverview',
+            '_controller' => '\Drupal\field_ui\Controller\FieldConfigListController::listing',
             '_title' => 'Manage fields',
           ) + $defaults,
           array('_permission' => 'administer ' . $entity_type_id . ' fields'),
@@ -99,6 +99,16 @@ protected function alterRoutes(RouteCollection $collection) {
         $collection->add("field_ui.overview_$entity_type_id", $route);
 
         $route = new Route(
+          "$path/add-field",
+          array(
+            '_form' => '\Drupal\field_ui\Form\FieldStorageAddForm',
+            '_title' => 'Add field',
+          ) + $defaults,
+          array('_permission' => 'administer ' . $entity_type_id . ' fields')
+        );
+        $collection->add("field_ui.field_storage_config_add_$entity_type_id", $route);
+
+        $route = new Route(
           "$path/form-display",
           array(
             '_form' => '\Drupal\field_ui\FormDisplayOverview',
diff --git a/core/modules/field_ui/src/Tests/FieldUIRouteTest.php b/core/modules/field_ui/src/Tests/FieldUIRouteTest.php
index 1f4d3ea..f88d7a2 100644
--- a/core/modules/field_ui/src/Tests/FieldUIRouteTest.php
+++ b/core/modules/field_ui/src/Tests/FieldUIRouteTest.php
@@ -19,7 +19,7 @@ class FieldUIRouteTest extends WebTestBase {
   /**
    * Modules to enable.
    */
-  public static $modules = array('field_ui_test');
+  public static $modules = array('entity_test', 'field_ui');
 
   /**
    * {@inheritdoc}
@@ -34,10 +34,8 @@ protected function setUp() {
    * Ensures that entity types with bundles do not break following entity types.
    */
   public function testFieldUIRoutes() {
-    $this->drupalGet('field-ui-test-no-bundle/manage/fields');
-    // @todo Bring back this assertion in https://drupal.org/node/1963340.
-    // @see \Drupal\field_ui\FieldOverview::getRegions()
-    //$this->assertText('No fields are present yet.');
+    $this->drupalGet('entity_test_no_id/structure/entity_test/fields');
+    $this->assertText('No fields are present yet.');
 
     $this->drupalGet('admin/config/people/accounts/fields');
     $this->assertTitle('Manage fields | Drupal');
diff --git a/core/modules/field_ui/src/Tests/FieldUiTestTrait.php b/core/modules/field_ui/src/Tests/FieldUiTestTrait.php
index d20fd91..57afdbe 100644
--- a/core/modules/field_ui/src/Tests/FieldUiTestTrait.php
+++ b/core/modules/field_ui/src/Tests/FieldUiTestTrait.php
@@ -34,19 +34,19 @@
   public function fieldUIAddNewField($bundle_path, $field_name, $label = NULL, $field_type = 'test_field', array $storage_edit = array(), array $field_edit = array()) {
     $label = $label ?: $this->randomString();
     $initial_edit = array(
-      'fields[_add_new_field][field_name]' => $field_name,
-      'fields[_add_new_field][type]' => $field_type,
-      'fields[_add_new_field][label]' => $label,
+      'type' => $field_type,
+      'label' => $label,
+      'field_name' => $field_name,
     );
 
     // Allow the caller to set a NULL path in case they navigated to the right
     // page before calling this method.
     if ($bundle_path !== NULL) {
-      $bundle_path = "$bundle_path/fields";
+      $bundle_path = "$bundle_path/add-field";
     }
 
-    // First step : 'Add new field' on the 'Manage fields' page.
-    $this->drupalPostForm($bundle_path,  $initial_edit, t('Save'));
+    // First step : 'Add field' page.
+    $this->drupalPostForm($bundle_path,  $initial_edit, t('Save and continue'));
     $this->assertRaw(t('These settings apply to the %label field everywhere it is used.', array('%label' => $label)), 'Storage settings page was displayed.');
     // Test Breadcrumbs.
     $this->assertLink($label, 0, 'Field label is correct in the breadcrumb of the storage settings page.');
@@ -80,15 +80,15 @@ public function fieldUIAddNewField($bundle_path, $field_name, $label = NULL, $fi
   public function fieldUIAddExistingField($bundle_path, $existing_field_name, $label = NULL, array $field_edit = array()) {
     $label = $label ?: $this->randomString();
     $initial_edit = array(
-      'fields[_add_existing_field][label]' => $label,
-      'fields[_add_existing_field][field_name]' => $existing_field_name,
+      'existing_field_name' => $existing_field_name,
     );
 
-    // First step : 'Re-use existing field' on the 'Manage fields' page.
-    $this->drupalPostForm("$bundle_path/fields", $initial_edit, t('Save'));
+    // First step: 'Re-use existing field' on the 'Add fields' page.
+    $this->drupalPostForm("$bundle_path/add-field", $initial_edit, t('Save and continue'));
     $this->assertNoRaw('&amp;lt;', 'The page does not have double escaped HTML tags.');
 
-    // Second step : 'Field settings' form.
+    // Second step: 'Field settings' form.
+    $field_edit += array('field[label]' => $label);
     $this->drupalPostForm(NULL, $field_edit, t('Save settings'));
     $this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), 'Redirected to "Manage fields" page.');
 
diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php
index 955034c..f6b4a14 100644
--- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php
@@ -118,11 +118,8 @@ function manageFieldsPage($type = '') {
       $this->assertRaw($table_header . '</th>', format_string('%table_header table header was found.', array('%table_header' => $table_header)));
     }
 
-    // "Add new field" and "Re-use existing field" aren't a table heading so just
-    // test the text.
-    foreach (array('Add new field', 'Re-use existing field') as $element) {
-      $this->assertText($element, format_string('"@element" was found.', array('@element' => $element)));
-    }
+    // Test the "Add field" action link.
+    $this->assertLink('Add field');
 
     // Assert entity operations for all fields.
     $result = $this->xpath('//ul[@class = "dropbutton"]/li/a');
@@ -178,12 +175,12 @@ function updateField() {
    */
   function addExistingField() {
     // Check "Re-use existing field" appears.
-    $this->drupalGet('admin/structure/types/manage/page/fields');
-    $this->assertRaw(t('Re-use existing field'), '"Re-use existing field" was found.');
+    $this->drupalGet('admin/structure/types/manage/page/add-field');
+    $this->assertRaw(t('Re-use an existing field'), '"Re-use existing field" was found.');
 
     // Check that fields of other entity types (here, the 'comment_body' field)
     // do not show up in the "Re-use existing field" list.
-    $this->assertFalse($this->xpath('//select[@id="edit-add-existing-field-field-name"]//option[@value="comment"]'), 'The list of options respects entity type restrictions.');
+    $this->assertFalse($this->xpath('//select[@id="edit-existing-field"]//option[@value="comment"]'), 'The list of options respects entity type restrictions.');
 
     // Add a new field based on an existing field.
     $this->fieldUIAddExistingField("admin/structure/types/manage/page", $this->field_name, $this->field_label . '_2');
@@ -254,8 +251,8 @@ protected function addPersistentFieldStorage() {
       $this->drupalPostForm(NULL, array(), t('Delete'));
     }
     // Check "Re-use existing field" appears.
-    $this->drupalGet('admin/structure/types/manage/page/fields');
-    $this->assertRaw(t('Re-use existing field'), '"Re-use existing field" was found.');
+    $this->drupalGet('admin/structure/types/manage/page/add-field');
+    $this->assertRaw(t('Re-use an existing field'), '"Re-use existing field" was found.');
     // Add a new field for the orphaned storage.
     $this->fieldUIAddExistingField("admin/structure/types/manage/page", $this->field_name);
   }
@@ -296,11 +293,11 @@ function testFieldPrefix() {
 
     // Try to create the field.
     $edit = array(
-      'fields[_add_new_field][label]' => $field_exceed_max_length_label,
-      'fields[_add_new_field][field_name]' => $field_exceed_max_length_input,
+      'label' => $field_exceed_max_length_label,
+      'field_name' => $field_exceed_max_length_input,
     );
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/fields', $edit, t('Save'));
-    $this->assertText('New field name cannot be longer than 22 characters but is currently 23 characters long.');
+    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/add-field', $edit, t('Save and continue'));
+    $this->assertText('Machine-readable name cannot be longer than 22 characters but is currently 23 characters long.');
 
     // Create a valid field.
     $this->fieldUIAddNewField('admin/structure/types/manage/' . $this->type, $this->field_name_input, $this->field_label);
@@ -409,20 +406,20 @@ function testDisallowedFieldNames() {
 
     $label = 'Disallowed field';
     $edit = array(
-      'fields[_add_new_field][label]' => $label,
-      'fields[_add_new_field][type]' => 'test_field',
+      'label' => $label,
+      'type' => 'test_field',
     );
 
     // Try with an entity key.
-    $edit['fields[_add_new_field][field_name]'] = 'title';
+    $edit['field_name'] = 'title';
     $bundle_path = 'admin/structure/types/manage/' . $this->type;
-    $this->drupalPostForm("$bundle_path/fields",  $edit, t('Save'));
+    $this->drupalPostForm("$bundle_path/add-field",  $edit, t('Save and continue'));
     $this->assertText(t('The machine-readable name is already in use. It must be unique.'));
 
     // Try with a base field.
-    $edit['fields[_add_new_field][field_name]'] = 'sticky';
+    $edit['field_name'] = 'sticky';
     $bundle_path = 'admin/structure/types/manage/' . $this->type;
-    $this->drupalPostForm("$bundle_path/fields",  $edit, t('Save'));
+    $this->drupalPostForm("$bundle_path/add-field",  $edit, t('Save and continue'));
     $this->assertText(t('The machine-readable name is already in use. It must be unique.'));
   }
 
@@ -467,11 +464,9 @@ function testLockedField() {
    * Tests that Field UI respects the 'no_ui' flag in the field type definition.
    */
   function testHiddenFields() {
-    $bundle_path = 'admin/structure/types/manage/' . $this->type . '/fields/';
-
     // Check that the field type is not available in the 'add new field' row.
-    $this->drupalGet($bundle_path);
-    $this->assertFalse($this->xpath('//select[@id="edit-fields-add-new-field-type"]//option[@value="hidden_test_field"]'), "The 'add new field' select respects field types 'no_ui' property.");
+    $this->drupalGet('admin/structure/types/manage/' . $this->type . '/add-field');
+    $this->assertFalse($this->xpath('//select[@id="edit-type"]//option[@value="hidden_test_field"]'), "The 'add new field' select respects field types 'no_ui' property.");
 
     // Create a field storage and a field programmatically.
     $field_name = 'hidden_test_field';
@@ -494,23 +489,22 @@ function testHiddenFields() {
 
     // Check that the newly added field appears on the 'Manage Fields'
     // screen.
-    $this->drupalGet($bundle_path);
+    $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields');
     $this->assertFieldByXPath('//table[@id="field-overview"]//tr[@id="hidden-test-field"]//td[1]', $field['label'], 'Field was created and appears in the overview page.');
 
     // Check that the field does not appear in the 're-use existing field' row
     // on other bundles.
-    $bundle_path = 'admin/structure/types/manage/article/fields/';
-    $this->drupalGet($bundle_path);
-    $this->assertFalse($this->xpath('//select[@id="edit-add-existing-field-field-name"]//option[@value=:field_name]', array(':field_name' => $field_name)), "The 're-use existing field' select respects field types 'no_ui' property.");
+    $this->drupalGet('admin/structure/types/manage/article/add-field');
+    $this->assertFalse($this->xpath('//select[@id="edit-existing-field"]//option[@value=:field_name]', array(':field_name' => $field_name)), "The 're-use existing field' select respects field types 'no_ui' property.");
 
     // Check that non-configurable fields are not available.
     $field_types = \Drupal::service('plugin.manager.field.field_type')->getDefinitions();
     foreach ($field_types as $field_type => $definition) {
       if (empty($definition['no_ui'])) {
-        $this->assertTrue($this->xpath('//select[@id="edit-fields-add-new-field-type"]//option[@value=:field_type]', array(':field_type' => $field_type)), String::format('Configurable field type @field_type is available.', array('@field_type' => $field_type)));
+        $this->assertTrue($this->xpath('//select[@id="edit-type"]//option[@value=:field_type]', array(':field_type' => $field_type)), String::format('Configurable field type @field_type is available.', array('@field_type' => $field_type)));
       }
       else {
-        $this->assertFalse($this->xpath('//select[@id="edit-fields-add-new-field-type"]//option[@value=:field_type]', array(':field_type' => $field_type)), String::format('Non-configurable field type @field_type is not available.', array('@field_type' => $field_type)));
+        $this->assertFalse($this->xpath('//select[@id="edit-type"]//option[@value=:field_type]', array(':field_type' => $field_type)), String::format('Non-configurable field type @field_type is not available.', array('@field_type' => $field_type)));
       }
     }
   }
@@ -535,12 +529,12 @@ function testDuplicateFieldName() {
     // field_tags already exists, so we're expecting an error when trying to
     // create a new field with the same name.
     $edit = array(
-      'fields[_add_new_field][field_name]' => 'tags',
-      'fields[_add_new_field][label]' => $this->randomMachineName(),
-      'fields[_add_new_field][type]' => 'taxonomy_term_reference',
+      'field_name' => 'tags',
+      'label' => $this->randomMachineName(),
+      'type' => 'taxonomy_term_reference',
     );
-    $url = 'admin/structure/types/manage/' . $this->type . '/fields';
-    $this->drupalPostForm($url, $edit, t('Save'));
+    $url = 'admin/structure/types/manage/' . $this->type . '/add-field';
+    $this->drupalPostForm($url, $edit, t('Save and continue'));
 
     $this->assertText(t('The machine-readable name is already in use. It must be unique.'));
     $this->assertUrl($url, array(), 'Stayed on the same page.');
diff --git a/core/modules/field_ui/tests/modules/field_ui_test/field_ui_test.info.yml b/core/modules/field_ui/tests/modules/field_ui_test/field_ui_test.info.yml
deleted file mode 100644
index 9d7a5d1..0000000
--- a/core/modules/field_ui/tests/modules/field_ui_test/field_ui_test.info.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-name: "Field UI tests"
-type: module
-description: "Support module for Field UI testing."
-package: Testing
-version: VERSION
-core: 8.x
-
-dependencies:
-  - field_ui
-  - entity_test
diff --git a/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php b/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php
deleted file mode 100644
index ec75368..0000000
--- a/core/modules/field_ui/tests/modules/field_ui_test/src/Entity/FieldUITestNoBundle.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\field_ui_test\Entity\FieldUITestNoBundle.
- */
-
-namespace Drupal\field_ui_test\Entity;
-
-use Drupal\entity_test\Entity\EntityTest;
-
-/**
- * Defines the test Field UI class.
- *
- * @ContentEntityType(
- *   id = "field_ui_test_no_bundle",
- *   label = @Translation("Test Field UI entity, no bundle"),
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *   }
- * )
- */
-class FieldUITestNoBundle extends EntityTest {
-
-}
