diff --git a/README.txt b/README.txt
index f9162f0..b3b95dc 100644
--- a/README.txt
+++ b/README.txt
@@ -1,16 +1,3 @@
-NEW BRANCH!
------------
-
-Drupal 8 now uses semantic versioning. If you are using Git, run
-
-$ git checkout 8.0.x
-
-If you download packaged archives, the new files are at
-https://www.drupal.org/node/2311847
-
-For more information about semantic versioning for Drupal core, see
-https://www.drupal.org/node/586146
-
 
 CONTENTS OF THIS FILE
 ---------------------
diff --git a/core/core.services.yml b/core/core.services.yml
index 562d64f..fd9028c 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -277,7 +277,7 @@ services:
     arguments: ['@menu.tree_storage', '@menu_link.static.overrides', '@module_handler']
   menu.link_tree:
     class: Drupal\Core\Menu\MenuLinkTree
-    arguments: ['@menu.tree_storage', '@plugin.manager.menu.link', '@router.route_provider', '@menu.active_trail', '@controller_resolver']
+    arguments: ['@menu.tree_storage', '@plugin.manager.menu.link', '@router.route_provider', '@menu.active_trail', '@controller_resolver', '@cache.menu', '@current_route_match']
   menu.default_tree_manipulators:
     class: Drupal\Core\Menu\DefaultMenuLinkTreeManipulators
     arguments: ['@access_manager', '@current_user']
@@ -443,7 +443,12 @@ services:
     arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver', '@state']
   router.rebuild_subscriber:
     class: Drupal\Core\EventSubscriber\RouterRebuildSubscriber
-    arguments: ['@router.builder', '@lock']
+    arguments: ['@router.builder']
+    tags:
+      - { name: event_subscriber }
+  menu.rebuild_subscriber:
+    class: Drupal\Core\EventSubscriber\MenuRouterRebuildSubscriber
+    arguments: ['@lock', '@plugin.manager.menu.link']
     tags:
       - { name: event_subscriber }
   path.alias_storage:
diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index 7ab2059..d779bd9 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -5,6 +5,8 @@
  * Functions for use with Drupal's Ajax framework.
  */
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * @defgroup ajax Ajax framework
  * @{
@@ -64,7 +66,7 @@
  *   return \Drupal::formBuilder()->getForm('ajax_example_simplest');
  * }
  *
- * function ajax_example_simplest($form, &$form_state) {
+ * function ajax_example_simplest($form, FormStateInterface $form_state) {
  *   $form = array();
  *   $form['changethis'] = array(
  *     '#type' => 'select',
@@ -236,7 +238,7 @@
  *
  * @see ajax_pre_render_element()
  */
-function ajax_process_form($element, &$form_state) {
+function ajax_process_form($element, FormStateInterface $form_state) {
   $element = ajax_pre_render_element($element);
   if (!empty($element['#ajax_processed'])) {
     $form_state['cache'] = TRUE;
diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index 02089bb..81f0654 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -17,6 +17,7 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\Timer;
 use Drupal\Core\Batch\Percentage;
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
@@ -442,6 +443,9 @@ function _batch_finished() {
     }
 
     // Determine the target path to redirect to.
+    if (!isset($_batch['form_state'])) {
+      $_batch['form_state'] = new FormState();
+    }
     if (!isset($_batch['form_state']['redirect'])) {
       if (isset($_batch['redirect'])) {
         $_batch['form_state']['redirect'] = $_batch['redirect'];
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 2e653ef..df5677f 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4184,58 +4184,3 @@ function drupal_get_filetransfer_info() {
   }
   return $info;
 }
-
-/**
- * @defgroup queue Queue operations
- * @{
- * Queue items to allow later processing.
- *
- * The queue system allows placing items in a queue and processing them later.
- * The system tries to ensure that only one consumer can process an item.
- *
- * Before a queue can be used it needs to be created by
- * Drupal\Core\Queue\QueueInterface::createQueue().
- *
- * Items can be added to the queue by passing an arbitrary data object to
- * Drupal\Core\Queue\QueueInterface::createItem().
- *
- * To process an item, call Drupal\Core\Queue\QueueInterface::claimItem() and
- * specify how long you want to have a lease for working on that item.
- * When finished processing, the item needs to be deleted by calling
- * Drupal\Core\Queue\QueueInterface::deleteItem(). If the consumer dies, the
- * item will be made available again by the Drupal\Core\Queue\QueueInterface
- * implementation once the lease expires. Another consumer will then be able to
- * receive it when calling Drupal\Core\Queue\QueueInterface::claimItem().
- * Due to this, the processing code should be aware that an item might be handed
- * over for processing more than once.
- *
- * The $item object used by the Drupal\Core\Queue\QueueInterface can contain
- * arbitrary metadata depending on the implementation. Systems using the
- * interface should only rely on the data property which will contain the
- * information passed to Drupal\Core\Queue\QueueInterface::createItem().
- * The full queue item returned by Drupal\Core\Queue\QueueInterface::claimItem()
- * needs to be passed to Drupal\Core\Queue\QueueInterface::deleteItem() once
- * processing is completed.
- *
- * There are two kinds of queue backends available: reliable, which preserves
- * the order of messages and guarantees that every item will be executed at
- * least once. The non-reliable kind only does a best effort to preserve order
- * in messages and to execute them at least once but there is a small chance
- * that some items get lost. For example, some distributed back-ends like
- * Amazon SQS will be managing jobs for a large set of producers and consumers
- * where a strict FIFO ordering will likely not be preserved. Another example
- * would be an in-memory queue backend which might lose items if it crashes.
- * However, such a backend would be able to deal with significantly more writes
- * than a reliable queue and for many tasks this is more important. See
- * aggregator_cron() for an example of how to effectively utilize a
- * non-reliable queue. Another example is doing Twitter statistics -- the small
- * possibility of losing a few items is insignificant next to power of the
- * queue being able to keep up with writes. As described in the processing
- * section, regardless of the queue being reliable or not, the processing code
- * should be aware that an item might be handed over for processing more than
- * once (because the processing code might time out before it finishes).
- */
-
-/**
- * @} End of "defgroup queue".
- */
diff --git a/core/includes/database.inc b/core/includes/database.inc
index 98b4022..d1fef5a 100644
--- a/core/includes/database.inc
+++ b/core/includes/database.inc
@@ -18,7 +18,7 @@
  * @{
  * Allow the use of different database servers using the same code base.
  *
- * @sec sec_intro Overview
+ * @section sec_intro Overview
  * Drupal's database abstraction layer provides a unified database query API
  * that can query different underlying databases. It is built upon PHP's
  * PDO (PHP Data Objects) database API, and inherits much of its syntax and
@@ -30,11 +30,11 @@
  * For more detailed information on the database abstraction layer, see
  * https://drupal.org/developing/api/database
  *
- * @sec sec_entity Querying entities
+ * @section sec_entity Querying entities
  * Any query on Drupal entities or fields should use the Entity Query API. See
  * the @link entity_api entity API topic @endlink for more information.
  *
- * @sec sec_simple Simple SELECT database queries
+ * @section sec_simple Simple SELECT database queries
  * For simple SELECT queries that do not involve entities, the Drupal database
  * abstraction layer provides the functions db_query() and db_query_range(),
  * which execute SELECT queries (optionally with range limits) and return result
@@ -90,7 +90,7 @@
  * ... array(':my_field' => 'foo') ...
  * @endcode
  *
- * @sec sec_dynamic Dynamic SELECT queries
+ * @section sec_dynamic Dynamic SELECT queries
  * For SELECT queries where the simple query API described in @ref sec_simple
  * will not work well, you need to use the dynamic query API. However, you
  * should still use the Entity Query API if your query involves entities or
@@ -115,7 +115,7 @@
  * @endcode
  *
  * There are also methods to join to other tables, add fields with aliases,
- * isNull() to have a @code WHERE e.foo IS NULL @code condition, etc. See
+ * isNull() to have a @code WHERE e.foo IS NULL @endcode condition, etc. See
  * https://drupal.org/developing/api/database for many more details.
  *
  * One note on chaining: It is common in the dynamic database API to chain
@@ -129,7 +129,7 @@
  * returns the query or something else, and only chain methods that return the
  * query.
  *
- * @sec_insert INSERT, UPDATE, and DELETE queries
+ * @section_insert INSERT, UPDATE, and DELETE queries
  * INSERT, UPDATE, and DELETE queries need special care in order to behave
  * consistently across databases; you should never use db_query() to run
  * an INSERT, UPDATE, or DELETE query. Instead, use functions db_insert(),
@@ -153,7 +153,7 @@
  *   ->execute();
  * @endcode
  *
- * @sec sec_transaction Tranactions
+ * @section sec_transaction Tranactions
  * Drupal supports transactions, including a transparent fallback for
  * databases that do not support transactions. To start a new transaction,
  * call @code $txn = db_transaction(); @endcode The transaction will
@@ -204,7 +204,7 @@
  * }
  * @endcode
  *
- * @sec sec_connection Database connection objects
+ * @section sec_connection Database connection objects
  * The examples here all use functions like db_select() and db_query(), which
  * can be called from any Drupal method or function code. In some classes, you
  * may already have a database connection object in a member variable, or it may
diff --git a/core/includes/form.inc b/core/includes/form.inc
index de7bc39..7131a7b 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -12,6 +12,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Database\Database;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\OptGroup;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
@@ -19,119 +20,6 @@
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
- * @defgroup form_api Form generation
- * @{
- * Describes how to generate and manipulate forms and process form submissions.
- *
- * Drupal provides a Form API in order to achieve consistency in its form
- * processing and presentation, while simplifying code and reducing the amount
- * of HTML that must be explicitly generated by a module.
- *
- * @section generating_forms Creating forms
- * Forms are defined as classes that implement the
- * \Drupal\Core\Form\FormInterface and are built using the
- * \Drupal\Core\Form\FormBuilder class. Drupal provides a couple of utility
- * classes that can be extended as a starting point for most basic forms, the
- * most commonly used of which is \Drupal\Core\Form\FormBase. FormBuilder
- * handles the low level processing of forms such as rendering the necessary
- * HTML, initial processing of incoming $_POST data, and delegating to your
- * implementation of FormInterface for validation and processing of submitted
- * data.
- *
- * Here is an example of a Form class:
- * @code
- * namespace Drupal\mymodule\Form;
- *
- * use Drupal\Core\Form\FormBase;
- *
- * class ExampleForm extends FormBase {
- *   public function getFormId() {
- *     // Unique ID of the form.
- *     return 'example_form';
- *   }
- *
- *   public function buildForm(array $form, array &$form_state) {
- *     // Create a $form API array.
- *     $form['phone_number'] = array(
- *       '#type' => 'tel',
- *       '#title' => $this->t('Your phone number')
- *     );
- *     return $form;
- *   }
- *
- *   public function validateForm(array &$form, array &$form_state) {
- *     // Validate submitted form data.
- *   }
- *
- *   public function submitForm(array &$form, array &$form_state) {
- *     // Handle submitted form data.
- *   }
- * }
- * @endcode
- *
- * @section retrieving_forms Retrieving and displaying forms
- * \Drupal::formBuilder()->getForm() should be used to handle retrieving,
- * processing, and displaying a rendered HTML form. Given the ExampleForm
- * defined above,
- * \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\ExampleForm') would
- * return the rendered HTML of the form defined by ExampleForm::buildForm(), or
- * call the validateForm() and submitForm(), methods depending on the current
- * processing state.
- *
- * The argument to \Drupal::formBuilder()->getForm() is the name of a class that
- * implements FormBuilderInterface. Any additional arguments passed to the
- * getForm() method will be passed along as additional arguments to the
- * ExampleForm::buildForm() method.
- *
- * For example:
- * @code
- * $extra = '612-123-4567';
- * $form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\ExampleForm', $extra);
- * ...
- * public function buildForm(array $form, array &$form_state, $extra = NULL)
- *   $form['phone_number'] = array(
- *     '#type' => 'tel',
- *     '#title' => $this->t('Your phone number'),
- *     '#value' => $extra,
- *   );
- *   return $form;
- * }
- * @endcode
- *
- * Alternatively, forms can be built directly via the routing system which will
- * take care of calling \Drupal::formBuilder()->getForm(). The following example
- * demonstrates the use of a routing.yml file to display a form at the the
- * given route.
- *
- * @code
- * example.form:
- *   path: '/example-form'
- *   defaults:
- *     _title: 'Example form'
- *     _form: '\Drupal\mymodule\Form\ExampleForm'
- * @endcode
- *
- * The $form argument to form-related functions is a structured array containing
- * the elements and properties of the form. For information on the array
- * components and format, and more detailed explanations of the Form API
- * workflow, see the
- * @link forms_api_reference.html Form API reference @endlink
- * and the
- * @link https://drupal.org/node/2117411 Form API documentation section. @endlink
- * In addition, there is a set of Form API tutorials in
- * @link form_example_tutorial.inc the Form Example Tutorial @endlink which
- * provide basics all the way up through multistep forms.
- *
- * In the form builder, validation, submission, and other form methods,
- * $form_state is the primary influence on the processing of the form and is
- * passed by reference to most methods, so they can use it to communicate with
- * the form system and each other.
- *
- * See \Drupal\Core\Form\FormBuilder::buildForm() for documentation of
- * $form_state keys.
- */
-
-/**
  * Fetches a form from the cache.
  *
  * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
@@ -139,7 +27,7 @@
  *
  * @see \Drupal\Core\Form\FormBuilderInterface::getCache().
  */
-function form_get_cache($form_build_id, &$form_state) {
+function form_get_cache($form_build_id, FormStateInterface $form_state) {
   return \Drupal::formBuilder()->getCache($form_build_id, $form_state);
 }
 
@@ -186,7 +74,7 @@ function form_set_cache($form_build_id, $form, $form_state) {
  *
  * @see module_load_include()
  */
-function form_load_include(&$form_state, $type, $module, $name = NULL) {
+function form_load_include(FormStateInterface $form_state, $type, $module, $name = NULL) {
   if (!isset($name)) {
     $name = $module;
   }
@@ -212,7 +100,7 @@ function form_load_include(&$form_state, $type, $module, $name = NULL) {
  *
  * @see \Drupal\Core\Form\FormBuilderInterface::submitForm().
  */
-function drupal_form_submit($form_arg, &$form_state) {
+function drupal_form_submit($form_arg, FormStateInterface $form_state) {
   \Drupal::formBuilder()->submitForm($form_arg, $form_state);
 }
 
@@ -224,7 +112,7 @@ function drupal_form_submit($form_arg, &$form_state) {
  *
  * @see \Drupal\Core\Form\FormBuilderInterface::retrieveForm().
  */
-function drupal_retrieve_form($form_id, &$form_state) {
+function drupal_retrieve_form($form_id, FormStateInterface $form_state) {
   return \Drupal::formBuilder()->retrieveForm($form_id, $form_state);
 
 }
@@ -236,7 +124,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
  *
  * @see \Drupal\Core\Form\FormBuilderInterface::processForm().
  */
-function drupal_process_form($form_id, &$form, &$form_state) {
+function drupal_process_form($form_id, &$form, FormStateInterface $form_state) {
   \Drupal::formBuilder()->processForm($form_id, $form, $form_state);
 }
 
@@ -262,7 +150,7 @@ function drupal_redirect_form($form_state) {
  * @see \Drupal\Core\Form\FormSubmitterInterface::executeSubmitHandlers()
  * @see \Drupal\Core\Form\FormValidatorInterface::executeValidateHandlers()
  */
-function form_execute_handlers($type, &$form, &$form_state) {
+function form_execute_handlers($type, &$form, FormStateInterface $form_state) {
   if ($type == 'submit') {
     \Drupal::service('form_submitter')->executeSubmitHandlers($form, $form_state);
   }
@@ -279,7 +167,7 @@ function form_execute_handlers($type, &$form, &$form_state) {
  *
  * @see \Drupal\Core\Form\FormErrorInterface::setErrorByName().
  */
-function form_set_error($name, array &$form_state, $message = '') {
+function form_set_error($name, FormStateInterface $form_state, $message = '') {
   \Drupal::formBuilder()->setErrorByName($name, $form_state, $message);
 }
 
@@ -291,7 +179,7 @@ function form_set_error($name, array &$form_state, $message = '') {
  *
  * @see \Drupal\Core\Form\FormErrorInterface::getErrors()
  */
-function form_get_errors(array &$form_state) {
+function form_get_errors(FormStateInterface $form_state) {
   return \Drupal::formBuilder()->getErrors($form_state);
 }
 
@@ -303,7 +191,7 @@ function form_get_errors(array &$form_state) {
  *
  * @see \Drupal\Core\Form\FormErrorInterface::getError().
  */
-function form_get_error($element, array &$form_state) {
+function form_get_error($element, FormStateInterface $form_state) {
   return \Drupal::formBuilder()->getError($element, $form_state);
 }
 
@@ -315,7 +203,7 @@ function form_get_error($element, array &$form_state) {
  *
  * @see \Drupal\Core\Form\FormErrorInterface::setError().
  */
-function form_error(&$element, array &$form_state, $message = '') {
+function form_error(&$element, FormStateInterface $form_state, $message = '') {
   \Drupal::formBuilder()->setError($element, $form_state, $message);
 }
 
@@ -327,7 +215,7 @@ function form_error(&$element, array &$form_state, $message = '') {
  *
  * @see \Drupal\Core\Form\FormBuilderInterface::doBuildForm().
  */
-function form_builder($form_id, &$element, &$form_state) {
+function form_builder($form_id, &$element, FormStateInterface $form_state) {
   return \Drupal::formBuilder()->doBuildForm($form_id, $element, $form_state);
 }
 
@@ -346,10 +234,9 @@ function form_builder($form_id, &$element, &$form_state) {
  * - op
  *
  * @param $form_state
- *   A keyed array containing the current state of the form, including
- *   submitted form values; altered by reference.
+ *   The current state of the form, including submitted form values.
  */
-function form_state_values_clean(&$form_state) {
+function form_state_values_clean(FormStateInterface $form_state) {
   // Remove internal Form API values.
   unset($form_state['values']['form_id'], $form_state['values']['form_token'], $form_state['values']['form_build_id'], $form_state['values']['op']);
 
@@ -395,7 +282,7 @@ function form_state_values_clean(&$form_state) {
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
  * @param $form_state
- *   A keyed array containing the current state of the form.
+ *   The current state of the form.
  *
  * @return
  *   The data that will appear in the $form_state['values'] collection
@@ -732,7 +619,7 @@ function form_type_token_value($element, $input = FALSE) {
  *
  * @see \Drupal\Core\Form\FormBuilderInterface::setValue().
  */
-function form_set_value($element, $value, &$form_state) {
+function form_set_value($element, $value, FormStateInterface $form_state) {
   \Drupal::formBuilder()->setValue($element, $value, $form_state);
 }
 
@@ -1368,12 +1255,12 @@ function form_process_checkboxes($element) {
  *   An associative array containing the properties and children of the
  *   form actions container.
  * @param $form_state
- *   The $form_state array for the form this element belongs to.
+ *   The current state of the form for the form this element belongs to.
  *
  * @return
  *   The processed element.
  */
-function form_process_actions($element, &$form_state) {
+function form_process_actions($element, FormStateInterface $form_state) {
   $element['#attributes']['class'][] = 'form-actions';
   return $element;
 }
@@ -1431,14 +1318,14 @@ function form_pre_render_actions_dropbutton(array $element) {
  *   An associative array containing the properties and children of the
  *   generic input element.
  * @param $form_state
- *   The $form_state array for the form this element belongs to.
+ *   The current state of the form for the form this element belongs to.
  *
  * @return
  *   The processed element.
  *
  * @see form_validate_pattern()
  */
-function form_process_pattern($element, &$form_state) {
+function form_process_pattern($element, FormStateInterface $form_state) {
   if (isset($element['#pattern']) && !isset($element['#attributes']['pattern'])) {
     $element['#attributes']['pattern'] = $element['#pattern'];
     $element['#element_validate'][] = 'form_validate_pattern';
@@ -1454,11 +1341,11 @@ function form_process_pattern($element, &$form_state) {
  *   An associative array containing the properties and children of the
  *   generic form element.
  * @param $form_state
- *   The $form_state array for the form this element belongs to.
+ *   The current state of the form for the form this element belongs to.
  *
  * @see form_process_pattern()
  */
-function form_validate_pattern($element, &$form_state) {
+function form_validate_pattern($element, FormStateInterface $form_state) {
   if ($element['#value'] !== '') {
     // The pattern must match the entire string and should have the same
     // behavior as the RegExp object in ECMA 262.
@@ -1481,12 +1368,12 @@ function form_validate_pattern($element, &$form_state) {
  *   An associative array containing the properties and children of the
  *   container.
  * @param $form_state
- *   The $form_state array for the form this element belongs to.
+ *   The current state of the form for the form this element belongs to.
  *
  * @return
  *   The processed element.
  */
-function form_process_container($element, &$form_state) {
+function form_process_container($element, FormStateInterface $form_state) {
   // Generate the ID of the element if it's not explicitly given.
   if (!isset($element['#id'])) {
     $element['#id'] = drupal_html_id(implode('-', $element['#parents']) . '-wrapper');
@@ -1681,7 +1568,7 @@ function form_process_tableselect($element) {
  * @param array $element
  *   An associative array containing the properties and children of the
  *   table element.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  *
  * @return array
@@ -1690,7 +1577,7 @@ function form_process_tableselect($element) {
  * @see form_process_tableselect()
  * @see theme_tableselect()
  */
-function form_process_table($element, &$form_state) {
+function form_process_table($element, FormStateInterface $form_state) {
   if ($element['#tableselect']) {
     if ($element['#multiple']) {
       $value = is_array($element['#value']) ? $element['#value'] : array();
@@ -1807,10 +1694,10 @@ function form_process_table($element, &$form_state) {
  * @param array $element
  *   An associative array containing the properties and children of the
  *   table element.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
-function form_validate_table($element, &$form_state) {
+function form_validate_table($element, FormStateInterface $form_state) {
   // Skip this validation if the button to submit the form does not require
   // selected table row data.
   if (empty($form_state['triggering_element']['#tableselect'])) {
@@ -1858,7 +1745,7 @@ function form_validate_table($element, &$form_state) {
  *   - #disabled: (optional) Should be set to TRUE in case an existing machine
  *     name must not be changed after initial creation.
  */
-function form_process_machine_name($element, &$form_state) {
+function form_process_machine_name($element, FormStateInterface $form_state) {
   // We need to pass the langcode to the client.
   $language = \Drupal::languageManager()->getCurrentLanguage();
 
@@ -1942,7 +1829,7 @@ function form_process_machine_name($element, &$form_state) {
  *
  * Note that #maxlength is validated by _form_validate() already.
  */
-function form_validate_machine_name(&$element, &$form_state) {
+function form_validate_machine_name(&$element, FormStateInterface $form_state) {
   // Verify that the machine name not only consists of replacement tokens.
   if (preg_match('@^' . $element['#machine_name']['replace'] . '+$@', $element['#value'])) {
     form_error($element, $form_state, t('The machine-readable name must contain unique characters.'));
@@ -1983,12 +1870,12 @@ function form_validate_machine_name(&$element, &$form_state) {
  *   element. Note that $element must be taken by reference here, so processed
  *   child elements are taken over into $form_state.
  * @param $form_state
- *   The $form_state array for the form this element belongs to.
+ *   The current state of the form for the form this element belongs to.
  *
  * @return
  *   The processed element.
  */
-function form_process_group(&$element, &$form_state) {
+function form_process_group(&$element, FormStateInterface $form_state) {
   $parents = implode('][', $element['#parents']);
 
   // Each details element forms a new group. The #type 'vertical_tabs' basically
@@ -2107,12 +1994,12 @@ function form_pre_render_group($element) {
  *   An associative array containing the properties and children of the
  *   details element.
  * @param $form_state
- *   The $form_state array for the form this vertical tab widget belongs to.
+ *   The current state of the form for the form this vertical tab widget belongs to.
  *
  * @return
  *   The processed element.
  */
-function form_process_vertical_tabs($element, &$form_state) {
+function form_process_vertical_tabs($element, FormStateInterface $form_state) {
   // Inject a new details as child, so that form_process_details() processes
   // this details element like any other details.
   $element['group'] = array(
@@ -2201,13 +2088,13 @@ function template_preprocess_vertical_tabs(&$variables) {
  *     autocomplete JavaScript library.
  *   - #autocomplete_route_parameters: The parameters to be used in conjunction
  *     with the route name.
- * @param array $form_state
- *   An associative array containing the current state of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @return array
  *   The form element.
  */
-function form_process_autocomplete($element, &$form_state) {
+function form_process_autocomplete($element, FormStateInterface $form_state) {
   $access = FALSE;
   if (!empty($element['#autocomplete_route_name'])) {
     $parameters = isset($element['#autocomplete_route_parameters']) ? $element['#autocomplete_route_parameters'] : array();
@@ -2367,7 +2254,7 @@ function form_pre_render_email($element) {
  *
  * Note that #maxlength and #required is validated by _form_validate() already.
  */
-function form_validate_email(&$element, &$form_state) {
+function form_validate_email(&$element, FormStateInterface $form_state) {
   $value = trim($element['#value']);
   form_set_value($element, $value, $form_state);
 
@@ -2438,7 +2325,7 @@ function form_pre_render_range($element) {
  *
  * Note that #required is validated by _form_validate() already.
  */
-function form_validate_number(&$element, &$form_state) {
+function form_validate_number(&$element, FormStateInterface $form_state) {
   $value = $element['#value'];
   if ($value === '') {
     return;
@@ -2546,7 +2433,7 @@ function form_pre_render_search($element) {
  *
  * Note that #maxlength and #required is validated by _form_validate() already.
  */
-function form_validate_url(&$element, &$form_state) {
+function form_validate_url(&$element, FormStateInterface $form_state) {
   $value = trim($element['#value']);
   form_set_value($element, $value, $form_state);
 
@@ -2558,7 +2445,7 @@ function form_validate_url(&$element, &$form_state) {
 /**
  * Form element validation handler for #type 'color'.
  */
-function form_validate_color(&$element, &$form_state) {
+function form_validate_color(&$element, FormStateInterface $form_state) {
   $value = trim($element['#value']);
 
   // Default to black if no value is given.
@@ -2929,10 +2816,6 @@ function _form_set_attributes(&$element, $class = array()) {
 }
 
 /**
- * @} End of "defgroup form_api".
- */
-
-/**
  * @defgroup batch Batch operations
  * @{
  * Creates and processes batch operations.
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 214ce28..121badc 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -7,6 +7,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\DatabaseExceptionWrapper;
 use Drupal\Core\Database\Install\TaskException;
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Installer\Exception\AlreadyInstalledException;
 use Drupal\Core\Installer\Exception\InstallerException;
 use Drupal\Core\Installer\Exception\NoProfilesException;
@@ -157,7 +158,7 @@ function install_drupal($settings = array()) {
  * submission is for, and the values are used as the $form_state['values']
  * array that is passed on to the form submission via drupal_form_submit()).
  *
- * @see drupal_form_submit()
+ * @see \Drupal\Core\Form\FormBuilderInterface::submitForm()
  */
 function install_state_defaults() {
   $defaults = array(
@@ -804,12 +805,12 @@ function install_tasks_to_display($install_state) {
 function install_get_form($form_id, array &$install_state) {
   // Ensure the form will not redirect, since install_run_tasks() uses a custom
   // redirection logic.
-  $form_state = array(
+  $form_state = new FormState(array(
     'build_info' => array(
       'args' => array(&$install_state),
     ),
     'no_redirect' => TRUE,
-  );
+  ));
   $form_builder = \Drupal::formBuilder();
   if ($install_state['interactive']) {
     $form = $form_builder->buildForm($form_id, $form_state);
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 8f1ce73..bd38752 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -153,8 +153,8 @@
  * - weight: Lower (negative) numbers come before higher (positive) numbers,
  *   for menu items with the same parent.
  *
- * Menu items from other modules can be altered using
- * hook_menu_link_defaults_alter().
+ * Discovered menu links from other modules can be altered using
+ * hook_menu_links_discovered_alter().
  *
  * @todo Derivatives will probably be defined for these; when they are, add
  *   documentation here.
@@ -256,135 +256,98 @@
  */
 
 /**
- * The maximum depth of a menu links tree - matches the number of p columns.
+ * @section Rendering menus
+ * Once you have created menus (that contain menu links), you want to render
+ * them. Drupal provides a block (Drupal\system\Plugin\Block\SystemMenuBlock) to
+ * do so.
+ *
+ * However, perhaps you have more advanced needs and you're not satisfied with
+ * what the menu blocks offer you. If that's the case, you'll want to:
+ * - Instantiate \Drupal\Core\Menu\MenuTreeParameters, and set its values to
+ *   match your needs. Alternatively, you can use
+ *   MenuLinkTree::getCurrentRouteMenuTreeParameters() to get a typical
+ *   default set of parameters, and then customize them to suit your needs.
+ * - Call \Drupal\Core\MenuLinkTree::load() with your menu link tree parameters,
+ *   this will return a menu link tree.
+ * - Pass the menu tree to \Drupal\Core\Menu\MenuLinkTree::transform() to apply
+ *   menu link tree manipulators that transform the tree. You will almost always
+ *   want to apply access checking. The manipulators that you will typically
+ *   need can be found in \Drupal\Core\Menu\DefaultMenuTreeManipulators.
+ * - Potentially write a custom menu tree manipulator, see
+ *   \Drupal\Core\Menu\DefaultMenuTreeManipulators for examples. This is only
+ *   necessary if you want to do things like adding extra metadata to rendered
+ *   links to display icons next to them.
+ * - Pass the menu tree to \Drupal\Core\Menu\MenuLinkTree::build(), this will
+ *   build a renderable array.
+ *
+ * Combined, that would look like this:
+ * @code
+ * $menu_tree = \Drupal::menuTree();
+ * $menu_name = 'my_menu';
  *
- * @todo Move this constant to MenuLinkStorage along with all the tree
- * functionality.
- */
-const MENU_MAX_DEPTH = 9;
-
-/**
- * Reserved key to identify the most specific menu link for a given path.
+ * // Build the typical default set of menu tree parameters.
+ * $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
  *
- * The value of this constant is a hash of the constant name. We use the hash
- * so that the reserved key is over 32 characters in length and will not
- * collide with allowed menu names:
- * @code
- * sha1('MENU_PREFERRED_LINK') = 1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91
- * @endcode
+ * // Load the tree based on this set of parameters.
+ * $tree = $menu_tree->load($menu_name, $parameters);
  *
- * @see menu_link_get_preferred()
- */
-const MENU_PREFERRED_LINK = '1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91';
-
-/**
- * Localizes a menu link title using t() if possible.
+ * // Transform the tree using the manipulators you want.
+ * $manipulators = array(
+ *   // Only show links that are accessible for the current user.
+ *   array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+ *   // Use the default sorting of menu links.
+ *   array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+ * );
+ * $tree = $menu_tree->transform($tree, $manipulators);
  *
- * Translate the title and description to allow storage of English title
- * strings in the database, yet display of them in the language required
- * by the current user.
+ * // Finally, build a renderable array from the transformed tree.
+ * $menu = $menu_tree->build($tree);
  *
- * @param $item
- *   A menu link entity.
+ * $menu_html = drupal_render($menu);
+ * @endcode
  */
-function _menu_item_localize(&$item) {
-  // Allow default menu links to be translated.
-  $item['localized_options'] = $item['options'];
-  // All 'class' attributes are assumed to be an array during rendering, but
-  // links stored in the database may use an old string value.
-  // @todo In order to remove this code we need to implement a database update
-  //   including unserializing all existing link options and running this code
-  //   on them, as well as adding validation to menu_link_save().
-  if (isset($item['options']['attributes']['class']) && is_string($item['options']['attributes']['class'])) {
-    $item['localized_options']['attributes']['class'] = explode(' ', $item['options']['attributes']['class']);
-  }
-  // If the menu link is defined in code and not customized, we can use t().
-  if (!empty($item['machine_name']) && !$item['customized']) {
-    // @todo Figure out a proper way to support translations of menu links, see
-    //   https://drupal.org/node/2193777.
-    $item['title'] = t($item['link_title']);
-  }
-  else {
-    $item['title'] = $item['link_title'];
-  }
-}
 
 /**
- * Provides menu link unserializing, access control, and argument handling.
- *
- * @param array $item
- *   The passed in item has the following keys:
- *   - access: (optional) Becomes TRUE if the item is accessible, FALSE
- *     otherwise. If the key is not set, the access manager is used to
- *     determine the access.
- *   - options: (required) Is unserialized and copied to $item['localized_options'].
- *   - link_title: (required) The title of the menu link.
- *   - route_name: (required) The route name of the menu link.
- *   - route_parameters: (required) The unserialized route parameters of the menu link.
- *   The passed in item is changed by the following keys:
- *   - href: The actual path to the link. This path is generated from the
- *     link_path of the menu link entity.
- *   - title: The title of the link. This title is generated from the
- *     link_title of the menu link entity.
+ * Implements template_preprocess_HOOK() for theme_menu_tree().
  */
-function _menu_link_translate(&$item) {
-  if (!is_array($item['options'])) {
-    $item['options'] = (array) unserialize($item['options']);
-  }
-  $item['localized_options'] = $item['options'];
-  $item['title'] = $item['link_title'];
-  if ($item['external'] || empty($item['route_name'])) {
-    $item['access'] = 1;
-    $item['href'] = $item['link_path'];
-    $item['route_parameters'] = array();
-    // Set to NULL so that drupal_pre_render_link() is certain to skip it.
-    $item['route_name'] = NULL;
-  }
-  else {
-    $item['href'] = NULL;
-    if (!is_array($item['route_parameters'])) {
-      $item['route_parameters'] = (array) unserialize($item['route_parameters']);
-    }
-    // menu_tree_check_access() may set this ahead of time for links to nodes.
-    if (!isset($item['access'])) {
-      $item['access'] = \Drupal::getContainer()->get('access_manager')->checkNamedRoute($item['route_name'], $item['route_parameters'], \Drupal::currentUser());
+function template_preprocess_menu_tree(&$variables) {
+  if (isset($variables['tree']['#heading'])) {
+    $variables['heading'] = $variables['tree']['#heading'];
+    $heading = &$variables['heading'];
+    // Convert a string heading into an array, using a H2 tag by default.
+    if (is_string($heading)) {
+      $heading = array('text' => $heading);
     }
-    // For performance, don't localize a link the user can't access.
-    if ($item['access']) {
-      _menu_item_localize($item);
+    // Merge in default array properties into $heading.
+    $heading += array(
+      'level' => 'h2',
+      'attributes' => array(),
+    );
+    // @todo Remove backwards compatibility for $heading['class'].
+    //   https://www.drupal.org/node/2310341
+    if (isset($heading['class'])) {
+      $heading['attributes']['class'] = $heading['class'];
     }
+    // Convert the attributes array into an Attribute object.
+    $heading['attributes'] = new Attribute($heading['attributes']);
+    $heading['text'] = String::checkPlain($heading['text']);
   }
 
-  // Allow other customizations - e.g. adding a page-specific query string to the
-  // options array. For performance reasons we only invoke this hook if the link
-  // has the 'alter' flag set in the options array.
-  if (!empty($item['options']['alter'])) {
-    \Drupal::moduleHandler()->alter('translated_menu_link', $item, $map);
+  if (isset($variables['tree']['#attributes'])) {
+    $variables['attributes'] = new Attribute($variables['tree']['#attributes']);
   }
-}
+  else {
+    $variables['attributes'] = new Attribute();
+  }
+  if (!isset($variables['attributes']['class'])) {
+    $variables['attributes']['class'] = array();
+  }
+  $variables['attributes']['class'][] = 'menu';
 
-/**
- * Implements template_preprocess_HOOK() for theme_menu_tree().
- */
-function template_preprocess_menu_tree(&$variables) {
   $variables['tree'] = $variables['tree']['#children'];
 }
 
 /**
- * Returns HTML for a wrapper for a menu sub-tree.
- *
- * @param $variables
- *   An associative array containing:
- *   - tree: An HTML string containing the tree's items.
- *
- * @see template_preprocess_menu_tree()
- * @ingroup themeable
- */
-function theme_menu_tree($variables) {
-  return '<ul class="menu">' . $variables['tree'] . '</ul>';
-}
-
-/**
  * Returns HTML for a menu link and submenu.
  *
  * @param $variables
@@ -400,8 +363,10 @@ function theme_menu_link(array $variables) {
   if ($element['#below']) {
     $sub_menu = drupal_render($element['#below']);
   }
-  $element['#localized_options']['set_active_class'] = TRUE;
-  $output = l($element['#title'], $element['#href'], $element['#localized_options']);
+  /** @var \Drupal\Core\Url $url */
+  $url = $element['#url'];
+  $url->setOption('set_active_class', TRUE);
+  $output = \Drupal::linkGenerator()->generateFromUrl($element['#title'], $url);
   return '<li' . new Attribute($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
 }
 
@@ -541,56 +506,28 @@ function _menu_get_links_source($name, $default) {
 }
 
 /**
- * Returns an array of links for a navigation menu.
+ * Builds a renderable array for a navigation menu.
  *
- * @param $menu_name
+ * @param string $menu_name
  *   The name of the menu.
- * @param $level
+ * @param int $level
  *   Optional, the depth of the menu to be returned.
  *
- * @return
- *   An array of links of the specified menu and level.
+ * @return array
+ *   A renderable array.
  */
 function menu_navigation_links($menu_name, $level = 0) {
-  // Don't even bother querying the menu table if no menu is specified.
-  if (empty($menu_name)) {
-    return array();
-  }
-
-  // Get the menu hierarchy for the current page.
-  /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-  $menu_tree = \Drupal::service('menu_link.tree');
-  $tree = $menu_tree->buildPageData($menu_name, $level + 1);
-
-  // Go down the active trail until the right level is reached.
-  while ($level-- > 0 && $tree) {
-    // Loop through the current level's items until we find one that is in trail.
-    while ($item = array_shift($tree)) {
-      if ($item['link']['in_active_trail']) {
-        // If the item is in the active trail, we continue in the subtree.
-        $tree = empty($item['below']) ? array() : $item['below'];
-        break;
-      }
-    }
-  }
-
-  // Create a single level of links.
-  $links = array();
-  foreach ($tree as $item) {
-    if (!$item['link']['hidden']) {
-      $class = '';
-      $l = $item['link']['localized_options'];
-      $l['href'] = $item['link']['link_path'];
-      $l['title'] = $item['link']['title'];
-      if ($item['link']['in_active_trail']) {
-        $class = ' active-trail';
-        $l['attributes']['class'][] = 'active-trail';
-      }
-      // Keyed with the unique mlid to generate classes in links.html.twig.
-      $links['menu-' . $item['link']['mlid'] . $class] = $l;
-    }
-  }
-  return $links;
+  $menu_tree = \Drupal::menuTree();
+  $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
+  $parameters->setMaxDepth($level + 1);
+  $tree = $menu_tree->load($menu_name, $parameters);
+  $manipulators = array(
+    array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+    array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    array('callable' => 'menu.default_tree_manipulators:extractSubtreeOfActiveTrail', 'args' => array($level)),
+  );
+  $tree = $menu_tree->transform($tree, $manipulators);
+  return $menu_tree->build($tree);
 }
 
 /**
@@ -734,355 +671,13 @@ function theme_menu_local_tasks(&$variables) {
 }
 
 /**
- * Sets (or gets) the active menu for the current page.
- *
- * The active menu for the page determines the active trail.
- *
- * @return
- *   An array of menu machine names, in order of preference. The
- *   'system.menu:active_menus_default' config item may be used to assert a menu
- *   order different from the order of creation, or to prevent a particular menu
- *   from being used at all in the active trail.
- */
-function menu_set_active_menu_names($menu_names = NULL) {
-  $active = &drupal_static(__FUNCTION__);
-
-  if (isset($menu_names) && is_array($menu_names)) {
-    $active = $menu_names;
-  }
-  elseif (!isset($active)) {
-    $config = \Drupal::config('system.menu');
-    $active = $config->get('active_menus_default') ?: array_keys(menu_list_system_menus());
-  }
-  return $active;
-}
-
-/**
- * Gets the active menu for the current page.
- */
-function menu_get_active_menu_names() {
-  return menu_set_active_menu_names();
-}
-
-/**
- * Looks up the preferred menu link for a given system path.
- *
- * @param $path
- *   The path; for example, 'node/5'. The function will find the corresponding
- *   menu link ('node/5' if it exists, or fallback to 'node/%').
- * @param $selected_menu
- *   The name of a menu used to restrict the search for a preferred menu link.
- *   If not specified, all the menus returned by menu_get_active_menu_names()
- *   will be used.
- *
- * @return
- *   A fully translated menu link, or FALSE if no matching menu link was
- *   found. The most specific menu link ('node/5' preferred over 'node/%') in
- *   the most preferred menu (as defined by menu_get_active_menu_names()) is
- *   returned.
- */
-function menu_link_get_preferred($path = NULL, $selected_menu = NULL) {
-  $preferred_links = &drupal_static(__FUNCTION__);
-
-  if (!isset($path)) {
-    $path = current_path();
-  }
-
-  if (empty($selected_menu)) {
-    // Use an illegal menu name as the key for the preferred menu link.
-    $selected_menu = MENU_PREFERRED_LINK;
-  }
-
-  if (!isset($preferred_links[$path])) {
-    // Look for the correct menu link by building a list of candidate paths,
-    // which are ordered by priority (translated hrefs are preferred over
-    // untranslated paths). Afterwards, the most relevant path is picked from
-    // the menus, ordered by menu preference.
-    $path_candidates = array();
-    // 1. The current item href.
-    // @todo simplify this code and convert to using route names.
-    // @see https://drupal.org/node/2154949
-    $path_candidates[$path] = $path;
-
-    // Retrieve a list of menu names, ordered by preference.
-    $menu_names = menu_get_active_menu_names();
-    // Put the selected menu at the front of the list.
-    array_unshift($menu_names, $selected_menu);
-
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => $path_candidates));
-
-    // Sort candidates by link path and menu name.
-    $candidates = array();
-    foreach ($menu_links as $candidate) {
-      $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
-      // Add any menus not already in the menu name search list.
-      if (!in_array($candidate['menu_name'], $menu_names)) {
-        $menu_names[] = $candidate['menu_name'];
-      }
-    }
-
-    // Store the most specific link for each menu. Also save the most specific
-    // link of the most preferred menu in $preferred_link.
-    foreach ($path_candidates as $link_path) {
-      if (isset($candidates[$link_path])) {
-        foreach ($menu_names as $menu_name) {
-          if (empty($preferred_links[$path][$menu_name]) && isset($candidates[$link_path][$menu_name])) {
-            $candidate_item = $candidates[$link_path][$menu_name];
-            $candidate_item['access'] = \Drupal::service('access_manager')->checkNamedRoute($candidate_item['route_name'], $candidate_item['route_parameters'], \Drupal::currentUser());
-            if ($candidate_item['access']) {
-              _menu_item_localize($candidate_item);
-              $preferred_links[$path][$menu_name] = $candidate_item;
-              if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) {
-                // Store the most specific link.
-                $preferred_links[$path][MENU_PREFERRED_LINK] = $candidate_item;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  return isset($preferred_links[$path][$selected_menu]) ? $preferred_links[$path][$selected_menu] : FALSE;
-}
-
-/**
  * Clears all cached menu data.
  *
  * This should be called any time broad changes
  * might have been made to the router items or menu links.
  */
 function menu_cache_clear_all() {
-  \Drupal::cache('data')->deleteAll();
-  menu_reset_static_cache();
-}
-
-/**
- * Resets the menu system static cache.
- */
-function menu_reset_static_cache() {
-  \Drupal::entityManager()
-    ->getStorage('menu_link')->resetCache();
-  drupal_static_reset('menu_link_get_preferred');
-}
-
-/**
- * Saves menu links recursively for menu_links_rebuild_defaults().
- */
-function _menu_link_save_recursive($controller, $machine_name, &$children, &$links) {
-  $menu_link = $links[$machine_name];
-  if ($menu_link->isNew() || !$menu_link->customized) {
-    if (!isset($menu_link->plid) && !empty($menu_link->parent) && !empty($links[$menu_link->parent])) {
-      $parent = $links[$menu_link->parent];
-
-      if (empty($menu_link->menu_name) || $parent->menu_name == $menu_link->menu_name) {
-        $menu_link->plid = $parent->id();
-        $menu_link->menu_name = $parent->menu_name;
-      }
-    }
-    $controller->save($menu_link);
-  }
-  if (!empty($children[$machine_name])) {
-    foreach ($children[$machine_name] as $next_name) {
-      _menu_link_save_recursive($controller, $next_name, $children, $links);
-    }
-  }
-  // Remove processed link names so we can find stragglers.
-  unset($children[$machine_name]);
-}
-
-/**
- * Builds menu links for the items returned from the menu_link.static service.
- */
-function menu_link_rebuild_defaults() {
-  // Ensure that all configuration used to build the menu items are loaded
-  // without overrides.
-  $old_state = \Drupal::configFactory()->getOverrideState();
-  \Drupal::configFactory()->setOverrideState(FALSE);
-  $module_handler = \Drupal::moduleHandler();
-  if (!$module_handler->moduleExists('menu_link')) {
-    // The Menu link module may not be available during install, so rebuild
-    // when possible.
-    return;
-  }
-  /** @var \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage */
-  $menu_link_storage = \Drupal::entityManager()
-    ->getStorage('menu_link');
-  $links = array();
-  $children = array();
-  $top_links = array();
-  $all_links = \Drupal::service('menu_link.static')->getLinks();
-  if ($all_links) {
-    foreach ($all_links as $machine_name => $link) {
-      // For performance reasons, do a straight query now and convert to a menu
-      // link entity later.
-      // @todo revisit before release.
-      $existing_item = db_select('menu_links')
-        ->fields('menu_links')
-        ->condition('machine_name', $machine_name)
-        ->execute()->fetchObject();
-      if ($existing_item) {
-        $existing_item->options = unserialize($existing_item->options);
-        $existing_item->route_parameters = unserialize($existing_item->route_parameters);
-        $link['mlid'] = $existing_item->mlid;
-        $link['plid'] = $existing_item->plid;
-        $link['uuid'] = $existing_item->uuid;
-        $link['customized'] = $existing_item->customized;
-        $link['updated'] = $existing_item->updated;
-        $menu_link = $menu_link_storage->createFromDefaultLink($link);
-        // @todo Do not create a new entity in order to update it, see
-        //   https://drupal.org/node/2241865
-        $menu_link->setOriginalId($existing_item->mlid);
-
-        // Convert the existing item to a typed object.
-        /** @var \Drupal\menu_link\MenuLinkInterface $existing_item */
-        $existing_item = $menu_link_storage->create(get_object_vars($existing_item));
-
-        if (!$existing_item->customized) {
-          // A change in the default menu links may move the link to a
-          // different menu or parent.
-          if (!empty($link['menu_name']) && ($link['menu_name'] != $existing_item->menu_name)) {
-            $menu_link->plid = NULL;
-            $menu_link->menu_name = $link['menu_name'];
-          }
-          elseif (!empty($link['parent'])) {
-            $menu_link->plid = NULL;
-          }
-
-          $menu_link->original = $existing_item;
-        }
-      }
-      else {
-        if (empty($link['route_name']) && empty($link['link_path'])) {
-          \Drupal::logger('menu_link')->error('Menu_link %machine_name does neither provide a route_name nor a link_path, so it got skipped.', array('%machine_name' => $machine_name));
-          continue;
-        }
-        $menu_link = $menu_link_storage->createFromDefaultLink($link);
-      }
-      if (!empty($link['parent'])) {
-        $children[$link['parent']][$machine_name] = $machine_name;
-        $menu_link->parent = $link['parent'];
-        if (empty($link['menu_name'])) {
-          // Reset the default menu name so it is populated from the parent.
-          $menu_link->menu_name = NULL;
-        }
-      }
-      else {
-        // A top level link - we need them to root our tree.
-        $top_links[$machine_name] = $machine_name;
-        $menu_link->plid = 0;
-      }
-      $links[$machine_name] = $menu_link;
-    }
-  }
-  foreach ($top_links as $machine_name) {
-    _menu_link_save_recursive($menu_link_storage, $machine_name, $children, $links);
-  }
-  // Handle any children we didn't find starting from top-level links.
-  foreach ($children as $orphan_links) {
-    foreach ($orphan_links as $machine_name) {
-      // Force it to the top level.
-      $links[$machine_name]->plid = 0;
-      _menu_link_save_recursive($menu_link_storage, $machine_name, $children, $links);
-    }
-  }
-
-  // Find any item whose default menu link no longer exists.
-  if ($all_links) {
-    $query = \Drupal::entityQuery('menu_link')
-      ->condition('machine_name', array_keys($all_links), 'NOT IN')
-      ->exists('machine_name')
-      ->condition('external', 0)
-      ->condition('updated', 0)
-      ->condition('customized', 0)
-      ->sort('depth', 'DESC');
-    $result = $query->execute();
-  }
-  else {
-    $result = array();
-  }
-
-  // Remove all such items. Starting from those with the greatest depth will
-  // minimize the amount of re-parenting done by the menu link controller.
-  if ($result) {
-    menu_link_delete_multiple($result, TRUE);
-  }
-  \Drupal::configFactory()->setOverrideState($old_state);
-}
-
-/**
- * Returns an array containing all links for a menu.
- *
- * @param $menu_name
- *   The name of the menu whose links should be returned.
- *
- * @return
- *   An array of menu links.
- */
-function menu_load_links($menu_name) {
-  $links = array();
-
-  $query = \Drupal::entityQuery('menu_link')
-    ->condition('menu_name', $menu_name)
-    // Order by weight so as to be helpful for menus that are only one level
-    // deep.
-    ->sort('weight');
-  $result = $query->execute();
-
-  if (!empty($result)) {
-    $links = menu_link_load_multiple($result);
-  }
-
-  return $links;
-}
-
-/**
- * Deletes all links for a menu.
- *
- * @param $menu_name
- *   The name of the menu whose links will be deleted.
- */
-function menu_delete_links($menu_name) {
-  $links = menu_load_links($menu_name);
-  menu_link_delete_multiple(array_keys($links), FALSE, TRUE);
-}
-
-/**
- * Updates the expanded menu item state at most twice per page load.
- */
-function _menu_update_expanded_menus() {
-  $expanded_menus_updated = &drupal_static(__FUNCTION__, 0);
-
-  // Update the expanded menu item state, but at most twice, including at
-  //  the end of the page load when there are multiple links saved or deleted.
-  if ($expanded_menus_updated == 0) {
-    // Keep track of which menus have expanded items.
-    _menu_set_expanded_menus();
-    $expanded_menus_updated = 1;
-  }
-  elseif ($expanded_menus_updated == 1) {
-    // Keep track of which menus have expanded items.
-    drupal_register_shutdown_function('_menu_set_expanded_menus');
-    $expanded_menus_updated = 2;
-  }
-}
-
-/**
- * Updates a list of menus with expanded items.
- */
-function _menu_set_expanded_menus() {
-  $names = array();
-  $result = Drupal::entityQueryAggregate('menu_link')
-    ->condition('expanded', 0, '<>')
-    ->groupBy('menu_name')
-    ->execute();
-
-  // Flatten the resulting array.
-  foreach($result as $k => $v) {
-    $names[$k] = $v['menu_name'];
-  }
-
-  \Drupal::state()->set('menu_expanded', $names);
+  \Drupal::cache('menu')->invalidateAll();
 }
 
 /**
diff --git a/core/includes/module.inc b/core/includes/module.inc
index 93dd924..023c102 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -176,93 +176,6 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE)
 }
 
 /**
- * @defgroup hooks Hooks
- * @{
- * Define functions that alter the behavior of Drupal core.
- *
- * One way for modules to alter the core behavior of Drupal (or another module)
- * is to use hooks. Hooks are specially-named functions that a module defines
- * (this is known as "implementing the hook"), which are discovered and called
- * at specific times to alter or add to the base behavior or data (this is
- * known as "invoking the hook"). Each hook has a name (example:
- * hook_batch_alter()), a defined set of parameters, and a defined return value.
- * Your modules can implement hooks that are defined by Drupal core or other
- * modules that they interact with. Your modules can also define their own
- * hooks, in order to let other modules interact with them.
- *
- * To implement a hook:
- * - Locate the documentation for the hook. Hooks are documented in *.api.php
- *   files, by defining functions whose name starts with "hook_" (these
- *   files and their functions are never loaded by Drupal -- they exist solely
- *   for documentation). The function should have a documentation header, as
- *   well as a sample function body. For example, in the core file
- *   system.api.php, you can find hooks such as hook_batch_alter(). Also, if
- *   you are viewing this documentation on an API reference site, the Core
- *   hooks will be listed in this topic.
- * - Copy the function to your module's .module file.
- * - Change the name of the function, substituting your module's short name
- *   (name of the module's directory, and .info.yml file without the extension)
- *   for the "hook" part of the sample function name. For instance, to implemnt
- *   hook_batch_alter(), you would rename it to my_module_batch_alter().
- * - Edit the documentation for the function (normally, your implementation
- *   should just have one line saying "Implements hook_batch_alter().").
- * - Edit the body of the function, substituting in what you need your module
- *   to do.
- *
- * To define a hook:
- * - Choose a unique name for your hook. It should start with "hook_", followed
- *   by your module's short name.
- * - Provide documentation in a *.api.php file in your module's main
- *   directory. See the "implementing" section above for details of what this
- *   should contain (parameters, return value, and sample function body).
- * - Invoke the hook in your module's code.
- *
- * To invoke a hook, use methods on
- * \Drupal\Core\Extension\ModuleHandlerInterface such as alter(), invoke(),
- * and invokeAll(). You can obtain a module handler by calling
- * \Drupal::moduleHandler(), or getting the 'module_handler' service on an
- * injected container.
- *
- * @see extending
- * @see themeable
- * @see callbacks
- * @see \Drupal\Core\Extension\ModuleHandlerInterface
- * @see \Drupal::moduleHandler()
- *
- * @}
- */
-
-/**
- * @defgroup callbacks Callbacks
- * @{
- * Callback function signatures.
- *
- * Drupal's API sometimes uses callback functions to allow you to define how
- * some type of processing happens. A callback is a function with a defined
- * signature, which you define in a module. Then you pass the function name as
- * a parameter to a Drupal API function or return it as part of a hook
- * implementation return value, and your function is called at an appropriate
- * time. For instance, when setting up batch processing you might need to
- * provide a callback function for each processing step and/or a callback for
- * when processing is finished; you would do that by defining these functions
- * and passing their names into the batch setup function.
- *
- * Callback function signatures, like hook definitions, are described by
- * creating and documenting dummy functions in a *.api.php file; normally, the
- * dummy callback function's name should start with "callback_", and you should
- * document the parameters and return value and provide a sample function body.
- * Then your API documentation can refer to this callback function in its
- * documentation. A user of your API can usually name their callback function
- * anything they want, although a standard name would be to replace "callback_"
- * with the module name.
- *
- * @see hooks
- * @see themeable
- *
- * @}
- */
-
-/**
  * Returns an array of modules required by core.
  */
 function drupal_required_modules() {
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 89cdc53..f23a864 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2145,27 +2145,17 @@ function template_preprocess_page(&$variables) {
 
   // Pass the main menu and secondary menu to the template as render arrays.
   if (!empty($variables['main_menu'])) {
-    $variables['main_menu'] = array(
-      '#theme' =>'links__system_main_menu',
-      '#links' => $variables['main_menu'],
-      '#heading' => array(
-        'text' => t('Main menu'),
-        'class' => array('visually-hidden'),
-        'attributes' => array('id' => 'links__system_main_menu'),
-      ),
-      '#set_active_class' => TRUE,
+    $variables['main_menu']['#heading'] = array(
+      'text' => t('Main menu'),
+      'class' => array('visually-hidden'),
+      'attributes' => array('id' => 'links__system_main_menu'),
     );
   }
   if (!empty($variables['secondary_menu'])) {
-    $variables['secondary_menu'] = array(
-      '#theme' =>'links__system_secondary_menu',
-      '#links' => $variables['secondary_menu'],
-      '#heading' => array(
-        'text' => t('Secondary menu'),
-        'class' => array('visually-hidden'),
-        'attributes' => array('id' => 'links__system_secondary_menu'),
-      ),
-      '#set_active_class' => TRUE,
+    $variables['secondary_menu']['#heading'] = array(
+      'text' => t('Secondary menu'),
+      'class' => array('visually-hidden'),
+      'attributes' => array('id' => 'links__system_secondary_menu'),
     );
   }
 
@@ -2651,6 +2641,7 @@ function drupal_common_theme() {
     ),
     'menu_tree' => array(
       'render element' => 'tree',
+      'template' => 'menu-tree',
     ),
     'menu_local_task' => array(
       'render element' => 'element',
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 21443e5..e20af77 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -647,4 +647,14 @@ public static function logger($channel) {
     return static::$container->get('logger.factory')->get($channel);
   }
 
+  /**
+   * Returns the menu tree.
+   *
+   * @return \Drupal\Core\Menu\MenuLinkTreeInterface
+   *   The menu tree.
+   */
+  public static function menuTree() {
+    return static::$container->get('menu.link_tree');
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Action/ConfigurableActionBase.php b/core/lib/Drupal/Core/Action/ConfigurableActionBase.php
index c32695b..e036880 100644
--- a/core/lib/Drupal/Core/Action/ConfigurableActionBase.php
+++ b/core/lib/Drupal/Core/Action/ConfigurableActionBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Core\Action\ActionBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 
 /**
@@ -49,7 +50,7 @@ public function setConfiguration(array $configuration) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Condition/ConditionPluginBase.php b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php
index 221e3b5..a745065 100644
--- a/core/lib/Drupal/Core/Condition/ConditionPluginBase.php
+++ b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Condition;
 
 use Drupal\Core\Executable\ExecutablePluginBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a basis for fulfilling contexts for condition plugins.
@@ -39,7 +40,7 @@ public function isNegated() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['negate'] = array(
       '#type' => 'checkbox',
       '#title' => $this->t('Negate the condition.'),
@@ -51,13 +52,13 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['negate'] = $form_state['values']['negate'];
   }
 
diff --git a/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php b/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php
index 3729f2d..ef02177 100644
--- a/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php
+++ b/core/lib/Drupal/Core/Config/Entity/DraggableListBuilder.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a class to build a draggable listing of configuration entities.
@@ -102,7 +103,7 @@ public function render() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form[$this->entitiesKey] = array(
       '#type' => 'table',
       '#header' => $this->buildHeader(),
@@ -138,14 +139,14 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // No validation.
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     foreach ($form_state['values'][$this->entitiesKey] as $id => $value) {
       if (isset($this->entities[$id]) && $this->entities[$id]->get($this->weightKey) != $value['weight']) {
         // Save entity only when its weight was changed.
diff --git a/core/lib/Drupal/Core/Controller/FormController.php b/core/lib/Drupal/Core/Controller/FormController.php
index a8c44e5..95e3eb5 100644
--- a/core/lib/Drupal/Core/Controller/FormController.php
+++ b/core/lib/Drupal/Core/Controller/FormController.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormState;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -66,7 +67,7 @@ public function getContentResult(Request $request) {
 
     // Add the form and form_state to trick the getArguments method of the
     // controller resolver.
-    $form_state = array();
+    $form_state = new FormState();
     $request->attributes->set('form', array());
     $request->attributes->set('form_state', $form_state);
     $args = $this->controllerResolver->getArguments($request, array($form_object, 'buildForm'));
diff --git a/core/lib/Drupal/Core/Display/VariantBase.php b/core/lib/Drupal/Core/Display/VariantBase.php
index ef7346d..b39d9b3 100644
--- a/core/lib/Drupal/Core/Display/VariantBase.php
+++ b/core/lib/Drupal/Core/Display/VariantBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Display;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Plugin\PluginDependencyTrait;
 use Drupal\Core\Session\AccountInterface;
@@ -100,7 +101,7 @@ public function calculateDependencies() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['label'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('Label'),
@@ -114,13 +115,13 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['label'] = $form_state['values']['label'];
   }
 
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php b/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
index 686cdae..fc5bd8e 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityConfirmFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\ConfirmFormHelper;
 use Drupal\Core\Form\ConfirmFormInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a generic base class for an entity-based confirmation form.
@@ -53,7 +54,7 @@ public function getFormName() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
     $form['#title'] = $this->getQuestion();
@@ -72,7 +73,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     // Do not attach fields to the confirm form.
     return $form;
   }
@@ -80,7 +81,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->getConfirmText();
     unset($actions['delete']);
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityForm.php b/core/lib/Drupal/Core/Entity/ContentEntityForm.php
index 8722a9c..d2fc480 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityForm.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity\Entity\EntityFormDisplay;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -47,7 +48,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
     $this->getFormDisplay($form_state)->buildForm($this->entity, $form, $form_state);
     return $form;
@@ -56,7 +57,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     $this->updateFormLangcode($form_state);
     $entity = $this->buildEntity($form, $form_state);
     $this->getFormDisplay($form_state)->validateFormValues($entity, $form, $form_state);
@@ -70,7 +71,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * Initialize the form state and the entity before the first form build.
    */
-  protected function init(array &$form_state) {
+  protected function init(FormStateInterface $form_state) {
     // Ensure we act on the translation object corresponding to the current form
     // language.
     $langcode = $this->getFormLangcode($form_state);
@@ -85,7 +86,7 @@ protected function init(array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function getFormLangcode(array &$form_state) {
+  public function getFormLangcode(FormStateInterface $form_state) {
     if (empty($form_state['langcode'])) {
       // Imply a 'view' operation to ensure users edit entities in the same
       // language they are displayed. This allows to keep contextual editing
@@ -98,14 +99,14 @@ public function getFormLangcode(array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function isDefaultFormLangcode(array $form_state) {
+  public function isDefaultFormLangcode(FormStateInterface $form_state) {
     return $this->getFormLangcode($form_state) == $this->entity->getUntranslated()->language()->id;
   }
 
   /**
    * {@inheritdoc}
    */
-  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, array &$form_state) {
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
     // First, extract values from widgets.
     $extracted = $this->getFormDisplay($form_state)->extractFormValues($entity, $form, $form_state);
 
@@ -122,14 +123,14 @@ protected function copyFormValuesToEntity(EntityInterface $entity, array $form,
   /**
    * {@inheritdoc}
    */
-  public function getFormDisplay(array $form_state) {
+  public function getFormDisplay(FormStateInterface $form_state) {
     return isset($form_state['form_display']) ? $form_state['form_display'] : NULL;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setFormDisplay(EntityFormDisplayInterface $form_display, array &$form_state) {
+  public function setFormDisplay(EntityFormDisplayInterface $form_display, FormStateInterface $form_state) {
     $form_state['form_display'] = $form_display;
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Entity/ContentEntityFormInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityFormInterface.php
index c006306..4d5cf4d 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityFormInterface.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityFormInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a common interface for content entity form classes.
@@ -17,13 +18,13 @@
   /**
    * Returns the form display.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface.
    *   The current form display.
    */
-  public function getFormDisplay(array $form_state);
+  public function getFormDisplay(FormStateInterface $form_state);
 
   /**
    * Sets the form display.
@@ -33,9 +34,9 @@ public function getFormDisplay(array $form_state);
    *
    * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
    *   The form display that the current form operates with.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function setFormDisplay(EntityFormDisplayInterface $form_display, array &$form_state);
+  public function setFormDisplay(EntityFormDisplayInterface $form_display, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Entity/Display/EntityFormDisplayInterface.php b/core/lib/Drupal/Core/Entity/Display/EntityFormDisplayInterface.php
index 7d8e3b5..4ecc887 100644
--- a/core/lib/Drupal/Core/Entity/Display/EntityFormDisplayInterface.php
+++ b/core/lib/Drupal/Core/Entity/Display/EntityFormDisplayInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity\Display;
 
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a common interface for entity form displays.
@@ -93,10 +94,10 @@
    *   $form_state['values']. If not specified, $form['#parents'] is set to an
    *   empty array, which results in field values located at the top-level of
    *   $form_state['values'].
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public function buildForm(ContentEntityInterface $entity, array &$form, array &$form_state);
+  public function buildForm(ContentEntityInterface $entity, array &$form, FormStateInterface $form_state);
 
   /**
    * Validates submitted widget values and sets the corresponding form errors.
@@ -122,10 +123,10 @@ public function buildForm(ContentEntityInterface $entity, array &$form, array &$
    * @param array $form
    *   The form structure where field elements are attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public function validateFormValues(ContentEntityInterface $entity, array &$form, array &$form_state);
+  public function validateFormValues(ContentEntityInterface $entity, array &$form, FormStateInterface $form_state);
 
   /**
    * Extracts field values from the submitted widget values into the entity.
@@ -138,7 +139,7 @@ public function validateFormValues(ContentEntityInterface $entity, array &$form,
    * @param array $form
    *   The form structure where field elements are attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    *
    * @return array
@@ -147,6 +148,6 @@ public function validateFormValues(ContentEntityInterface $entity, array &$form,
    *   any, do not correspond to widgets and should be extracted manually by
    *   the caller if needed.
    */
-  public function extractFormValues(ContentEntityInterface $entity, array &$form, array &$form_state);
+  public function extractFormValues(ContentEntityInterface $entity, array &$form, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityConfirmFormBase.php b/core/lib/Drupal/Core/Entity/EntityConfirmFormBase.php
index a86d646..d01d4af 100644
--- a/core/lib/Drupal/Core/Entity/EntityConfirmFormBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityConfirmFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\ConfirmFormHelper;
 use Drupal\Core\Form\ConfirmFormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -56,7 +57,7 @@ public function getFormName() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
     $form['#title'] = $this->getQuestion();
@@ -75,7 +76,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->getConfirmText();
     unset($actions['delete']);
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index dcb9aae..f929a95 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 
 /**
@@ -87,7 +88,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // During the initial form build, add this controller to the form state and
     // allow for initial preparation before form building and processing.
     if (!isset($form_state['controller'])) {
@@ -109,13 +110,13 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * Initialize the form state and the entity before the first form build.
    */
-  protected function init(array &$form_state) {
+  protected function init(FormStateInterface $form_state) {
     // Add the controller to the form state so it can be easily accessed by
     // module-provided form handlers there.
     $form_state['controller'] = $this;
@@ -133,7 +134,7 @@ protected function init(array &$form_state) {
    *
    * @see \Drupal\Core\Entity\EntityForm::build()
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
 
     // Add a process callback.
@@ -156,7 +157,7 @@ public function form(array $form, array &$form_state) {
    *
    * @see \Drupal\Core\Entity\EntityForm::form()
    */
-  public function processForm($element, $form_state, $form) {
+  public function processForm($element, FormStateInterface $form_state, $form) {
     // If the form is cached, process callbacks may not have a valid reference
     // to the entity object, hence we must restore it.
     $this->entity = $form_state['controller']->getEntity();
@@ -167,7 +168,7 @@ public function processForm($element, $form_state, $form) {
   /**
    * Returns the action form element for the current entity form.
    */
-  protected function actionsElement(array $form, array &$form_state) {
+  protected function actionsElement(array $form, FormStateInterface $form_state) {
     $element = $this->actions($form, $form_state);
 
     if (isset($element['delete'])) {
@@ -204,7 +205,7 @@ protected function actionsElement(array $form, array &$form_state) {
    * @todo Consider introducing a 'preview' action here, since it is used by
    *   many entity types.
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     // @todo Rename the action key from submit to save.
     $actions['submit'] = array(
       '#type' => 'submit',
@@ -242,7 +243,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     $this->updateFormLangcode($form_state);
     // @todo Remove this.
     // Execute legacy global validation handlers.
@@ -261,10 +262,10 @@ public function validate(array $form, array &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // Remove button and internal Form API values from submitted values.
     form_state_values_clean($form_state);
     $this->entity = $this->buildEntity($form, $form_state);
@@ -276,24 +277,24 @@ public function submit(array $form, array &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     // @todo Perform common save operations.
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getFormLangcode(array &$form_state) {
+  public function getFormLangcode(FormStateInterface $form_state) {
     return $this->entity->language()->id;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function isDefaultFormLangcode(array $form_state) {
+  public function isDefaultFormLangcode(FormStateInterface $form_state) {
     // The entity is not translatable, this is always the default language.
     return TRUE;
   }
@@ -301,10 +302,10 @@ public function isDefaultFormLangcode(array $form_state) {
   /**
    * Updates the form language to reflect any change to the entity language.
    *
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  protected function updateFormLangcode(array &$form_state) {
+  protected function updateFormLangcode(FormStateInterface $form_state) {
     // Update the form language as it might have changed.
     if (isset($form_state['values']['langcode']) && $this->isDefaultFormLangcode($form_state)) {
       $form_state['langcode'] = $form_state['values']['langcode'];
@@ -314,7 +315,7 @@ protected function updateFormLangcode(array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     $entity = clone $this->entity;
     // If you submit a form, the form state comes from caching, which forces
     // the controller to be the one before caching. Ensure to have the
@@ -344,10 +345,10 @@ public function buildEntity(array $form, array &$form_state) {
    *   The entity the current form should operate upon.
    * @param array $form
    *   A nested array of form elements comprising the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, array &$form_state) {
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
     // @todo: This relies on a method that only exists for config and content
     //   entities, in a different way. Consider moving this logic to a config
     //   entity specific implementation.
@@ -381,10 +382,10 @@ protected function prepareEntity() {}
    *
    * @param string $hook
    *   The hook variant name.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  protected function prepareInvokeAll($hook, array &$form_state) {
+  protected function prepareInvokeAll($hook, FormStateInterface $form_state) {
     $implementations = $this->moduleHandler->getImplementations($hook);
     foreach ($implementations as $module) {
       $function = $module . '_' . $hook;
diff --git a/core/lib/Drupal/Core/Entity/EntityFormBuilder.php b/core/lib/Drupal/Core/Entity/EntityFormBuilder.php
index c875754..3a825be 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormBuilder.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormState;
 
 /**
  * Builds entity forms.
@@ -44,10 +45,11 @@ public function __construct(EntityManagerInterface $entity_manager, FormBuilderI
   /**
    * {@inheritdoc}
    */
-  public function getForm(EntityInterface $entity, $operation = 'default', array $form_state = array()) {
+  public function getForm(EntityInterface $entity, $operation = 'default', array $form_state_additions = array()) {
     $form_object = $this->entityManager->getFormObject($entity->getEntityTypeId(), $operation);
     $form_object->setEntity($entity);
 
+    $form_state = new FormState($form_state_additions);
     $form_state['build_info']['callback_object'] = $form_object;
     $form_state['build_info']['base_form_id'] = $form_object->getBaseFormID();
     $form_state['build_info'] += array('args' => array());
diff --git a/core/lib/Drupal/Core/Entity/EntityFormBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityFormBuilderInterface.php
index 888abdb..584595f 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormBuilderInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormBuilderInterface.php
@@ -24,9 +24,9 @@
    *   _entity_form: node.book_outline
    *   @endcode
    *   where "book_outline" is the value of $operation.
-   * @param array $form_state
-   *   (optional) An associative array containing the current state of the form.
-   *   Use this to pass additional information to the form, such as the
+   * @param array $form_state_additions
+   *   (optional) An associative array used to build the current state of the
+   *   form. Use this to pass additional information to the form, such as the
    *   langcode. Defaults to an empty array.
    *
    * @code
@@ -37,6 +37,6 @@
    * @return array
    *   The processed form for the given entity and operation.
    */
-  public function getForm(EntityInterface $entity, $operation = 'default', array $form_state = array());
+  public function getForm(EntityInterface $entity, $operation = 'default', array $form_state_additions = array());
 
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityFormInterface.php b/core/lib/Drupal/Core/Entity/EntityFormInterface.php
index f1aeaa8..31f485a 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\BaseFormIdInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 
 /**
@@ -19,24 +20,24 @@
   /**
    * Returns the code identifying the active form language.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return string
    *   The form language code.
    */
-  public function getFormLangcode(array &$form_state);
+  public function getFormLangcode(FormStateInterface $form_state);
 
   /**
    * Checks whether the current form language matches the entity one.
    *
-   * @param array $form_state
-   *   A keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return boolean
    *   Returns TRUE if the entity form language matches the entity one.
    */
-  public function isDefaultFormLangcode(array $form_state);
+  public function isDefaultFormLangcode(FormStateInterface $form_state);
 
   /**
    * Sets the operation for this form.
@@ -61,8 +62,8 @@ public function getOperation();
    *
    * The form entity which has been used for populating form element defaults.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return \Drupal\Core\Entity\EntityInterface
    *   The current form entity.
@@ -96,23 +97,23 @@ public function setEntity(EntityInterface $entity);
    *
    * @param array $form
    *   A nested array form elements comprising the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return \Drupal\Core\Entity\EntityInterface
    *   An updated copy of the form's entity object.
    */
-  public function buildEntity(array $form, array &$form_state);
+  public function buildEntity(array $form, FormStateInterface $form_state);
 
   /**
    * Validates the submitted form values of the entity form.
    *
    * @param array $form
    *   A nested array form elements comprising the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function validate(array $form, array &$form_state);
+  public function validate(array $form, FormStateInterface $form_state);
 
   /**
    * Updates the form's entity by processing this submission's values.
@@ -123,10 +124,10 @@ public function validate(array $form, array &$form_state);
    *
    * @param array $form
    *   A nested array form elements comprising the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function submit(array $form, array &$form_state);
+  public function submit(array $form, FormStateInterface $form_state);
 
   /**
    * Sets the string translation service for this form.
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index facca39..23ce020 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -255,10 +255,7 @@ protected function getTableMapping($table, $entity_type_id) {
       $mapping = $storage->getTableMapping()->getAllColumns($table);
     }
     else {
-      // @todo Stop calling drupal_get_schema() once menu links are converted
-      //   to the Entity Field API. See https://drupal.org/node/1842858.
-      $schema = drupal_get_schema($table);
-      $mapping = array_keys($schema['fields']);
+      return FALSE;
     }
     return array_flip($mapping);
   }
diff --git a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php
similarity index 59%
copy from core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
copy to core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php
index 87fdb87..4b0b41f 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php
@@ -2,24 +2,22 @@
 
 /**
  * @file
- * Contains \Drupal\Core\EventSubscriber\RouterRebuildSubscriber.
+ * Contains \Drupal\Core\EventSubscriber\MenuRouterRebuildSubscriber.
  */
 
 namespace Drupal\Core\EventSubscriber;
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Lock\LockBackendInterface;
-use Drupal\Core\Routing\RouteBuilderInterface;
+use Drupal\Core\Menu\MenuLinkManagerInterface;
 use Drupal\Core\Routing\RoutingEvents;
 use Symfony\Component\EventDispatcher\Event;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\Event\PostResponseEvent;
-use Symfony\Component\HttpKernel\KernelEvents;
 
 /**
  * Rebuilds the default menu links and runs menu-specific code if necessary.
  */
-class RouterRebuildSubscriber implements EventSubscriberInterface {
+class MenuRouterRebuildSubscriber implements EventSubscriberInterface {
 
   /**
    * @var \Drupal\Core\Routing\RouteBuilderInterface
@@ -32,26 +30,23 @@ class RouterRebuildSubscriber implements EventSubscriberInterface {
   protected $lock;
 
   /**
-   * Constructs the RouterRebuildSubscriber object.
+   * The menu link plugin manager.
    *
-   * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
-   *   The route builder.
-   * @param \Drupal\Core\Lock\LockBackendInterface $lock
-   *   The lock backend.
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
    */
-  public function __construct(RouteBuilderInterface $route_builder, LockBackendInterface $lock) {
-    $this->routeBuilder = $route_builder;
-    $this->lock = $lock;
-  }
+  protected $menuLinkManager;
 
   /**
-   * Rebuilds routers if necessary.
+   * Constructs the MenuRouterRebuildSubscriber object.
    *
-   * @param \Symfony\Component\HttpKernel\Event\PostResponseEvent $event
-   *   The event object.
+   * @param \Drupal\Core\Lock\LockBackendInterface $lock
+   *   The lock backend.
+   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
+   *   The menu link plugin manager.
    */
-  public function onKernelTerminate(PostResponseEvent $event) {
-    $this->routeBuilder->rebuildIfNeeded();
+  public function __construct(LockBackendInterface $lock, MenuLinkManagerInterface $menu_link_manager) {
+    $this->lock = $lock;
+    $this->menuLinkManager = $menu_link_manager;
   }
 
   /**
@@ -73,11 +68,9 @@ protected function menuLinksRebuild() {
       $transaction = db_transaction();
       try {
         // Ensure the menu links are up to date.
-        menu_link_rebuild_defaults();
-        // Clear the menu cache.
-        menu_cache_clear_all();
-        // Track which menu items are expanded.
-        _menu_update_expanded_menus();
+        $this->menuLinkManager->rebuild();
+        // Ignore any database replicas temporarily.
+        db_ignore_replica();
       }
       catch (\Exception $e) {
         $transaction->rollback();
@@ -95,13 +88,9 @@ protected function menuLinksRebuild() {
   }
 
   /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
+   * {@inheritdoc}
    */
   static function getSubscribedEvents() {
-    $events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
     $events[RoutingEvents::FINISHED][] = array('onRouterRebuild', 200);
     return $events;
   }
diff --git a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
index 87fdb87..584b141 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php
@@ -17,7 +17,7 @@
 use Symfony\Component\HttpKernel\KernelEvents;
 
 /**
- * Rebuilds the default menu links and runs menu-specific code if necessary.
+ * Rebuilds the router if needed at the end of the request.
  */
 class RouterRebuildSubscriber implements EventSubscriberInterface {
 
@@ -27,21 +27,13 @@ class RouterRebuildSubscriber implements EventSubscriberInterface {
   protected $routeBuilder;
 
   /**
-   * @var \Drupal\Core\Lock\LockBackendInterface
-   */
-  protected $lock;
-
-  /**
    * Constructs the RouterRebuildSubscriber object.
    *
    * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
    *   The route builder.
-   * @param \Drupal\Core\Lock\LockBackendInterface $lock
-   *   The lock backend.
    */
-  public function __construct(RouteBuilderInterface $route_builder, LockBackendInterface $lock) {
+  public function __construct(RouteBuilderInterface $route_builder) {
     $this->routeBuilder = $route_builder;
-    $this->lock = $lock;
   }
 
   /**
@@ -55,54 +47,10 @@ public function onKernelTerminate(PostResponseEvent $event) {
   }
 
   /**
-   * Rebuilds the menu links and deletes the local_task cache tag.
-   *
-   * @param \Symfony\Component\EventDispatcher\Event $event
-   *   The event object.
-   */
-  public function onRouterRebuild(Event $event) {
-    $this->menuLinksRebuild();
-    Cache::deleteTags(array('local_task' => 1));
-  }
-
-  /**
-   * Perform menu-specific rebuilding.
-   */
-  protected function menuLinksRebuild() {
-    if ($this->lock->acquire(__FUNCTION__)) {
-      $transaction = db_transaction();
-      try {
-        // Ensure the menu links are up to date.
-        menu_link_rebuild_defaults();
-        // Clear the menu cache.
-        menu_cache_clear_all();
-        // Track which menu items are expanded.
-        _menu_update_expanded_menus();
-      }
-      catch (\Exception $e) {
-        $transaction->rollback();
-        watchdog_exception('menu', $e);
-      }
-
-      $this->lock->release(__FUNCTION__);
-    }
-    else {
-      // Wait for another request that is already doing this work.
-      // We choose to block here since otherwise the router item may not
-      // be available during routing resulting in a 404.
-      $this->lock->wait(__FUNCTION__);
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
+   * {@inheritdoc}
    */
   static function getSubscribedEvents() {
     $events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
-    $events[RoutingEvents::FINISHED][] = array('onRouterRebuild', 200);
     return $events;
   }
 
diff --git a/core/lib/Drupal/Core/Field/FieldItemBase.php b/core/lib/Drupal/Core/Field/FieldItemBase.php
index a22375e..715bbb7 100644
--- a/core/lib/Drupal/Core/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Field/FieldItemBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Field;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\TypedData\Plugin\DataType\Map;
 use Drupal\Core\TypedData\TypedDataInterface;
@@ -244,14 +245,14 @@ public function deleteRevision() { }
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     return array();
   }
 
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     return array();
   }
 
diff --git a/core/lib/Drupal/Core/Field/FieldItemInterface.php b/core/lib/Drupal/Core/Field/FieldItemInterface.php
index 25bad4e..b3a9269 100644
--- a/core/lib/Drupal/Core/Field/FieldItemInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldItemInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\ComplexDataInterface;
 
 /**
@@ -333,7 +334,7 @@ public static function instanceSettingsFromConfigData(array $settings);
    *
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    * @param bool $has_data
    *   TRUE if the field already has data, FALSE if not.
@@ -341,7 +342,7 @@ public static function instanceSettingsFromConfigData(array $settings);
    * @return
    *   The form definition for the field settings.
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data);
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data);
 
   /**
    * Returns a form for the instance-level settings.
@@ -351,12 +352,12 @@ public function settingsForm(array &$form, array &$form_state, $has_data);
    *
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    *
    * @return array
    *   The form definition for the field instance settings.
    */
-  public function instanceSettingsForm(array $form, array &$form_state);
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php
index 0c6559c..726572f 100644
--- a/core/lib/Drupal/Core/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Field/FieldItemList.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -301,7 +302,7 @@ public function getConstraints() {
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesForm(array &$form, array &$form_state) {
+  public function defaultValuesForm(array &$form, FormStateInterface $form_state) {
     if (empty($this->getFieldDefinition()->default_value_function)) {
       // Place the input in a separate place in the submitted values tree.
       $widget = $this->defaultValueWidget($form_state);
@@ -316,7 +317,7 @@ public function defaultValuesForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesFormValidate(array $element, array &$form, array &$form_state) {
+  public function defaultValuesFormValidate(array $element, array &$form, FormStateInterface $form_state) {
     // Extract the submitted value, and validate it.
     $widget = $this->defaultValueWidget($form_state);
     $widget->extractFormValues($this, $element, $form_state);
@@ -331,7 +332,7 @@ public function defaultValuesFormValidate(array $element, array &$form, array &$
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) {
+  public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) {
     // Extract the submitted value, and return it as an array.
     $widget = $this->defaultValueWidget($form_state);
     $widget->extractFormValues($this, $element, $form_state);
@@ -348,13 +349,13 @@ public static function processDefaultValue($default_value, ContentEntityInterfac
   /**
    * Returns the widget object used in default value form.
    *
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    *
    * @return \Drupal\Core\Field\WidgetInterface
    *   A Widget object.
    */
-  protected function defaultValueWidget(array &$form_state) {
+  protected function defaultValueWidget(FormStateInterface $form_state) {
     if (!isset($form_state['default_value_widget'])) {
       $entity = $this->getEntity();
 
diff --git a/core/lib/Drupal/Core/Field/FieldItemListInterface.php b/core/lib/Drupal/Core/Field/FieldItemListInterface.php
index 0a1583b..ddfe26b 100644
--- a/core/lib/Drupal/Core/Field/FieldItemListInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldItemListInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Field;
 
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Access\AccessibleInterface;
 use Drupal\Core\TypedData\ListInterface;
@@ -188,13 +189,13 @@ public function view($display_options = array());
    *
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    *
    * @return array
    *   The form definition for the field instance default value.
    */
-  public function defaultValuesForm(array &$form, array &$form_state);
+  public function defaultValuesForm(array &$form, FormStateInterface $form_state);
 
   /**
    * Validates the submitted default value.
@@ -206,10 +207,10 @@ public function defaultValuesForm(array &$form, array &$form_state);
    *   The default value form element.
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    */
-  public function defaultValuesFormValidate(array $element, array &$form, array &$form_state);
+  public function defaultValuesFormValidate(array $element, array &$form, FormStateInterface $form_state);
 
   /**
    * Processes the submitted default value.
@@ -221,13 +222,13 @@ public function defaultValuesFormValidate(array $element, array &$form, array &$
    *   The default value form element.
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    *
    * @return array
    *   The field instance default value.
    */
-  public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state);
+  public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state);
 
   /**
    * Processes the default value before being applied.
diff --git a/core/lib/Drupal/Core/Field/FormatterBase.php b/core/lib/Drupal/Core/Field/FormatterBase.php
index ed309a9..a3ad53e 100644
--- a/core/lib/Drupal/Core/Field/FormatterBase.php
+++ b/core/lib/Drupal/Core/Field/FormatterBase.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Field;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Base class for 'Field formatter' plugin implementations.
  *
@@ -106,7 +108,7 @@ public function view(FieldItemListInterface $items) {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     return array();
   }
 
diff --git a/core/lib/Drupal/Core/Field/FormatterInterface.php b/core/lib/Drupal/Core/Field/FormatterInterface.php
index 9db9857..8596e6b 100644
--- a/core/lib/Drupal/Core/Field/FormatterInterface.php
+++ b/core/lib/Drupal/Core/Field/FormatterInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Field;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Interface definition for field formatter plugins.
  *
@@ -23,13 +25,13 @@
    *
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The form elements for the formatter settings.
    */
-  public function settingsForm(array $form, array &$form_state);
+  public function settingsForm(array $form, FormStateInterface $form_state);
 
   /**
    * Returns a short summary for the current formatter settings.
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/DecimalFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/DecimalFormatter.php
index 4a0436b..0e43ac1 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/DecimalFormatter.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/DecimalFormatter.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Plugin implementation of the 'number_decimal' formatter.
  *
@@ -40,7 +42,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements = parent::settingsForm($form, $form_state);
 
     $elements['decimal_separator'] = array(
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php
index cc360b9..dc0fe82 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Parent plugin for decimal and integer formatters.
@@ -18,7 +19,7 @@
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $options = array(
       ''  => t('- None -'),
       '.' => t('Decimal point'),
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php
index fd20d22..6819f79 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/BooleanItem.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemBase;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\AllowedValuesInterface;
 use Drupal\Core\TypedData\DataDefinition;
@@ -64,7 +65,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element['on_label'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('"On" label'),
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
index 10d03b3..3f371fb 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/DecimalItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 
 /**
@@ -63,7 +64,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element = array();
     $settings = $this->getSettings();
 
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
index 41a7032..28846bb 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Base class for numeric configurable field types.
@@ -29,7 +30,7 @@ public static function defaultInstanceSettings() {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
     $settings = $this->getSettings();
 
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
index 711a9b2..3069af3 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'boolean_checkbox' widget.
@@ -36,7 +37,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['display_label'] = array(
       '#type' => 'checkbox',
       '#title' => t('Use field label instead of the "On label" as label'),
@@ -61,7 +62,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element['value'] = $element + array(
       '#type' => 'checkbox',
       '#default_value' => !empty($items[0]->value),
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
index 15bc2cc..ce60ebc 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'email_default' widget.
@@ -35,7 +36,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['placeholder'] = array(
       '#type' => 'textfield',
       '#title' => t('Placeholder'),
@@ -65,7 +66,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element['value'] = $element + array(
       '#type' => 'email',
       '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
index fa31ce7..0f5020c 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -38,7 +39,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['placeholder'] = array(
       '#type' => 'textfield',
       '#title' => t('Placeholder'),
@@ -68,7 +69,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $value = isset($items[$delta]->value) ? $items[$delta]->value : NULL;
     $field_settings = $this->getFieldSettings();
 
@@ -113,7 +114,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     return $element['value'];
   }
 
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
index fae98b1..8658dd0 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'string_textarea' widget.
@@ -36,7 +37,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['rows'] = array(
       '#type' => 'number',
       '#title' => t('Rows'),
@@ -71,7 +72,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element['value'] = $element + array(
       '#type' => 'textarea',
       '#default_value' => $items[$delta]->value,
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php
index ed1d928..853e661 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'string' widget.
@@ -36,7 +37,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['size'] = array(
       '#type' => 'number',
       '#title' => t('Size of textfield'),
@@ -71,7 +72,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element['value'] = $element + array(
       '#type' => 'textfield',
       '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
index 39606c6..8be947c 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'uri' widget.
@@ -36,7 +37,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['size'] = array(
       '#type' => 'number',
       '#title' => $this->t('Size of URI field'),
@@ -71,7 +72,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element['value'] = $element + array(
       '#type' => 'url',
       '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php
index 1fe4939..89f501c 100644
--- a/core/lib/Drupal/Core/Field/WidgetBase.php
+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 use Symfony\Component\Validator\ConstraintViolationListInterface;
 
@@ -58,7 +59,7 @@ public function __construct($plugin_id, $plugin_definition, FieldDefinitionInter
   /**
    * {@inheritdoc}
    */
-  public function form(FieldItemListInterface $items, array &$form, array &$form_state, $get_delta = NULL) {
+  public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL) {
     $field_name = $this->fieldDefinition->getName();
     $parents = $form['#parents'];
 
@@ -140,7 +141,7 @@ public function form(FieldItemListInterface $items, array &$form, array &$form_s
    * - AHAH-'add more' button
    * - table display and drag-n-drop value reordering
    */
-  protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
+  protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
     $field_name = $this->fieldDefinition->getName();
     $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
     $parents = $form['#parents'];
@@ -238,7 +239,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
    * This stores the final location of the field within the form structure so
    * that flagErrors() can assign validation errors to the right form element.
    */
-  public static function afterBuild(array $element, array &$form_state) {
+  public static function afterBuild(array $element, FormStateInterface $form_state) {
     $parents = $element['#field_parents'];
     $field_name = $element['#field_name'];
 
@@ -252,7 +253,7 @@ public static function afterBuild(array $element, array &$form_state) {
   /**
    * Submission handler for the "Add another item" button.
    */
-  public static function addMoreSubmit(array $form, array &$form_state) {
+  public static function addMoreSubmit(array $form, FormStateInterface $form_state) {
     $button = $form_state['triggering_element'];
 
     // Go one level up in the form, to the widgets container.
@@ -274,7 +275,7 @@ public static function addMoreSubmit(array $form, array &$form_state) {
    * This returns the new page content to replace the page content made obsolete
    * by the form submission.
    */
-  public static function addMoreAjax(array $form, array $form_state) {
+  public static function addMoreAjax(array $form, FormStateInterface $form_state) {
     $button = $form_state['triggering_element'];
 
     // Go one level up in the form, to the widgets container.
@@ -296,7 +297,7 @@ public static function addMoreAjax(array $form, array $form_state) {
   /**
    * Generates the form element for a single copy of the widget.
    */
-  protected function formSingleElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  protected function formSingleElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $entity = $items->getEntity();
 
     $element += array(
@@ -327,7 +328,7 @@ protected function formSingleElement(FieldItemListInterface $items, $delta, arra
   /**
    * {@inheritdoc}
    */
-  public function extractFormValues(FieldItemListInterface $items, array $form, array &$form_state) {
+  public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
     $field_name = $this->fieldDefinition->getName();
 
     // Extract the values from $form_state['values'].
@@ -372,7 +373,7 @@ public function extractFormValues(FieldItemListInterface $items, array $form, ar
   /**
    * {@inheritdoc}
    */
-  public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, array &$form_state) {
+  public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
     $field_name = $this->fieldDefinition->getName();
 
     $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
@@ -441,15 +442,15 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
   /**
    * {@inheritdoc}
    */
-  public static function getWidgetState(array $parents, $field_name, array &$form_state) {
-    return NestedArray::getValue($form_state, static::getWidgetStateParents($parents, $field_name));
+  public static function getWidgetState(array $parents, $field_name, FormStateInterface $form_state) {
+    return NestedArray::getValue($form_state['storage'], static::getWidgetStateParents($parents, $field_name));
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function setWidgetState(array $parents, $field_name, array &$form_state, array $field_state) {
-    NestedArray::setValue($form_state, static::getWidgetStateParents($parents, $field_name), $field_state);
+  public static function setWidgetState(array $parents, $field_name, FormStateInterface $form_state, array $field_state) {
+    NestedArray::setValue($form_state['storage'], static::getWidgetStateParents($parents, $field_name), $field_state);
   }
 
   /**
@@ -473,7 +474,7 @@ protected static function getWidgetStateParents(array $parents, $field_name) {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     return array();
   }
 
@@ -487,14 +488,14 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
     return $element;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function massageFormValues(array $values, array $form, array &$form_state) {
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     return $values;
   }
 
diff --git a/core/lib/Drupal/Core/Field/WidgetBaseInterface.php b/core/lib/Drupal/Core/Field/WidgetBaseInterface.php
index 0d52c1c..db7e0e7 100644
--- a/core/lib/Drupal/Core/Field/WidgetBaseInterface.php
+++ b/core/lib/Drupal/Core/Field/WidgetBaseInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationListInterface;
 
 /**
@@ -32,15 +33,15 @@
    * @param array $form
    *   An array representing the form that the editing element will be attached
    *   to.
-   * @param array $form_state
-   *   An array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param int $get_delta
    *   Used to get only a specific delta value of a multiple value field.
    *
    * @return array
    *   The form element array created for this field.
    */
-  public function form(FieldItemListInterface $items, array &$form, array &$form_state, $get_delta = NULL);
+  public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL);
 
   /**
    * Extracts field values from submitted form values.
@@ -51,10 +52,10 @@ public function form(FieldItemListInterface $items, array &$form, array &$form_s
    * @param array $form
    *   The form structure where field elements are attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public function extractFormValues(FieldItemListInterface $items, array $form, array &$form_state);
+  public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state);
 
   /**
    * Reports field-level validation errors against actual form elements.
@@ -66,10 +67,10 @@ public function extractFormValues(FieldItemListInterface $items, array $form, ar
    * @param array $form
    *   The form structure where field elements are attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, array &$form_state);
+  public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state);
 
   /**
    * Retrieves processing information about the widget from $form_state.
@@ -80,7 +81,7 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
    *   The array of #parents where the field lives in the form.
    * @param string $field_name
    *   The field name.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    *
    * @return array
@@ -89,7 +90,7 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
    *   - array_parents: The location of the field's widgets within the $form
    *     structure. This entry is populated at '#after_build' time.
    */
-  public static function getWidgetState(array $parents, $field_name, array &$form_state);
+  public static function getWidgetState(array $parents, $field_name, FormStateInterface $form_state);
 
   /**
    * Stores processing information about the widget in $form_state.
@@ -100,12 +101,12 @@ public static function getWidgetState(array $parents, $field_name, array &$form_
    *   The array of #parents where the widget lives in the form.
    * @param string $field_name
    *   The field name.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    * @param array $field_state
    *   The array of data to store. See getWidgetState() for the structure and
    *   content of the array.
    */
-  public static function setWidgetState(array $parents, $field_name, array &$form_state, array $field_state);
+  public static function setWidgetState(array $parents, $field_name, FormStateInterface $form_state, array $field_state);
 
 }
diff --git a/core/lib/Drupal/Core/Field/WidgetInterface.php b/core/lib/Drupal/Core/Field/WidgetInterface.php
index feb5d9a..90034a8 100644
--- a/core/lib/Drupal/Core/Field/WidgetInterface.php
+++ b/core/lib/Drupal/Core/Field/WidgetInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -30,13 +31,13 @@
    *
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The form definition for the widget settings.
    */
-  public function settingsForm(array $form, array &$form_state);
+  public function settingsForm(array $form, FormStateInterface $form_state);
 
   /**
    * Returns a short summary for the current widget settings.
@@ -97,8 +98,8 @@ public function settingsSummary();
    * @param array $form
    *   The form structure where widgets are being attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The form elements for a single widget for this field.
@@ -106,7 +107,7 @@ public function settingsSummary();
    * @see hook_field_widget_form_alter()
    * @see hook_field_widget_WIDGET_TYPE_form_alter()
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state);
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state);
 
   /**
    * Assigns a field-level validation error to the right widget sub-element.
@@ -122,14 +123,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
    * @param array $form
    *   The form structure where field elements are attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array|bool
    *   The element on which the error should be flagged, or FALSE to completely
    *   ignore the violation (use with care!).
    */
-  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, array &$form_state);
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state);
 
   /**
    * Massages the form values into the format expected for field values.
@@ -144,12 +145,12 @@ public function errorElement(array $element, ConstraintViolationInterface $viola
    * @param array $form
    *   The form structure where field elements are attached to. This might be a
    *   full form structure, or a sub-element of a larger form.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    *
    * @return array
    *   An array of field values, keyed by delta.
    */
-  public function massageFormValues(array $values, array $form, array &$form_state);
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/FileTransfer/Form/FileTransferAuthorizeForm.php b/core/lib/Drupal/Core/FileTransfer/Form/FileTransferAuthorizeForm.php
index 765d955..818f345 100644
--- a/core/lib/Drupal/Core/FileTransfer/Form/FileTransferAuthorizeForm.php
+++ b/core/lib/Drupal/Core/FileTransfer/Form/FileTransferAuthorizeForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\FileTransfer\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 
 /**
@@ -25,7 +26,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // If possible, we want to post this form securely via HTTPS.
     $form['#https'] = TRUE;
 
@@ -138,7 +139,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Only validate the form if we have collected all of the user input and are
     // ready to proceed with updating or installing.
     if ($form_state['triggering_element']['#name'] != 'process_updates') {
@@ -168,7 +169,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     switch ($form_state['triggering_element']['#name']) {
       case 'process_updates':
 
diff --git a/core/lib/Drupal/Core/Form/ConfigFormBase.php b/core/lib/Drupal/Core/Form/ConfigFormBase.php
index 8ed7403..f58bc11 100644
--- a/core/lib/Drupal/Core/Form/ConfigFormBase.php
+++ b/core/lib/Drupal/Core/Form/ConfigFormBase.php
@@ -36,9 +36,9 @@ public static function create(ContainerInterface $container) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['actions']['#type'] = 'actions';
     $form['actions']['submit'] = array(
       '#type' => 'submit',
@@ -53,9 +53,9 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The configuration options have been saved.'));
   }
 
diff --git a/core/lib/Drupal/Core/Form/ConfirmFormBase.php b/core/lib/Drupal/Core/Form/ConfirmFormBase.php
index d44ab47..2896690 100644
--- a/core/lib/Drupal/Core/Form/ConfirmFormBase.php
+++ b/core/lib/Drupal/Core/Form/ConfirmFormBase.php
@@ -43,7 +43,7 @@ public function getFormName() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->getQuestion();
 
     $form['#attributes']['class'][] = 'confirmation';
diff --git a/core/lib/Drupal/Core/Form/FormBase.php b/core/lib/Drupal/Core/Form/FormBase.php
index b9f04c1..e90dcf6 100644
--- a/core/lib/Drupal/Core/Form/FormBase.php
+++ b/core/lib/Drupal/Core/Form/FormBase.php
@@ -47,13 +47,6 @@
   protected $configFactory;
 
   /**
-   * The form error handler.
-   *
-   * @var \Drupal\Core\Form\FormErrorInterface
-   */
-  protected $errorHandler;
-
-  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
@@ -63,7 +56,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Validation is optional.
   }
 
@@ -174,34 +167,23 @@ private function container() {
   }
 
   /**
-   * Returns the form error handler.
-   *
-   * @return \Drupal\Core\Form\FormErrorInterface
-   *   The form error handler.
-   */
-  protected function errorHandler() {
-    if (!$this->errorHandler) {
-      $this->errorHandler = \Drupal::service('form_builder');
-    }
-    return $this->errorHandler;
-  }
-
-  /**
    * Files an error against a form element.
    *
    * @param string $name
    *   The name of the form element.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $message
    *   (optional) The error message to present to the user.
    *
-   * @see \Drupal\Core\Form\FormErrorInterface::setErrorByName()
+   * @deprecated Use \Drupal\Core\Form\FormStateInterface::setErrorByName().
+   *
+   * @todo Remove in https://www.drupal.org/node/2308821.
    *
    * @return $this
    */
-  protected function setFormError($name, array &$form_state, $message = '') {
-    $this->errorHandler()->setErrorByName($name, $form_state, $message);
+  protected function setFormError($name, FormStateInterface $form_state, $message = '') {
+    $form_state->setErrorByName($name, $message);
     return $this;
   }
 
diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index c150c29..c92f2d6 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -136,7 +136,7 @@ public function __construct(FormValidatorInterface $form_validator, FormSubmitte
   /**
    * {@inheritdoc}
    */
-  public function getFormId($form_arg, &$form_state) {
+  public function getFormId($form_arg, FormStateInterface &$form_state) {
     // If the $form_arg is the name of a class, instantiate it. Don't allow
     // arbitrary strings to be passed to the class resolver.
     if (is_string($form_arg) && class_exists($form_arg)) {
@@ -148,9 +148,9 @@ public function getFormId($form_arg, &$form_state) {
     }
 
     // Add the $form_arg as the callback object and determine the form ID.
-    $form_state['build_info']['callback_object'] = $form_arg;
+    $form_state->addBuildInfo('callback_object', $form_arg);
     if ($form_arg instanceof BaseFormIdInterface) {
-      $form_state['build_info']['base_form_id'] = $form_arg->getBaseFormID();
+      $form_state->addBuildInfo('base_form_id', $form_arg->getBaseFormID());
     }
     return $form_arg->getFormId();
   }
@@ -159,12 +159,12 @@ public function getFormId($form_arg, &$form_state) {
    * {@inheritdoc}
    */
   public function getForm($form_arg) {
-    $form_state = array();
+    $form_state = new FormState();
 
     $args = func_get_args();
     // Remove $form_arg from the arguments.
     unset($args[0]);
-    $form_state['build_info']['args'] = array_values($args);
+    $form_state->addBuildInfo('args', array_values($args));
 
     return $this->buildForm($form_arg, $form_state);
   }
@@ -172,16 +172,13 @@ public function getForm($form_arg) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm($form_id, array &$form_state) {
-    // Ensure some defaults; if already set they will not be overridden.
-    $form_state += $this->getFormStateDefaults();
-
+  public function buildForm($form_id, FormStateInterface &$form_state) {
     // Ensure the form ID is prepared.
     $form_id = $this->getFormId($form_id, $form_state);
 
     if (!isset($form_state['input'])) {
       $request = $this->requestStack->getCurrentRequest();
-      $form_state['input'] = $form_state['method'] == 'get' ? $request->query->all() : $request->request->all();
+      $form_state->set('input', $form_state['method'] == 'get' ? $request->query->all() : $request->request->all());
     }
 
     if (isset($_SESSION['batch_form_state'])) {
@@ -210,19 +207,19 @@ public function buildForm($form_id, array &$form_state) {
       // keys need to be removed after retrieving and preparing the form, except
       // any that were already set prior to retrieving the form.
       if ($check_cache) {
-        $form_state_before_retrieval = $form_state;
+        $form_state_before_retrieval = clone $form_state;
       }
 
       $form = $this->retrieveForm($form_id, $form_state);
       $this->prepareForm($form_id, $form, $form_state);
 
-      // self::setCache() removes uncacheable $form_state keys defined in
-      // self::getUncacheableKeys() in order for multi-step forms to work
+      // self::setCache() removes uncacheable $form_state keys (see properties
+      // in \Drupal\Core\Form\FormState) in order for multi-step forms to work
       // properly. This means that form processing logic for single-step forms
       // using $form_state['cache'] may depend on data stored in those keys
-      // during self::retrieveForm()/self::prepareForm(), but form
-      // processing should not depend on whether the form is cached or not, so
-      // $form_state is adjusted to match what it would be after a
+      // during self::retrieveForm()/self::prepareForm(), but form processing
+      // should not depend on whether the form is cached or not, so $form_state
+      // is adjusted to match what it would be after a
       // self::setCache()/self::getCache() sequence. These exceptions are
       // allowed to survive here:
       // - always_process: Does not make sense in conjunction with form caching
@@ -231,9 +228,9 @@ public function buildForm($form_id, array &$form_state) {
       // - temporary: Any assigned data is expected to survives within the same
       //   page request.
       if ($check_cache) {
-        $uncacheable_keys = array_flip(array_diff($this->getUncacheableKeys(), array('always_process', 'temporary')));
-        $form_state = array_diff_key($form_state, $uncacheable_keys);
-        $form_state += $form_state_before_retrieval;
+        $cache_form_state = $form_state->getCacheableArray(array('always_process', 'temporary'));
+        $form_state = $form_state_before_retrieval;
+        $form_state->setFormState($cache_form_state);
       }
     }
 
@@ -270,36 +267,7 @@ public function buildForm($form_id, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function getFormStateDefaults() {
-    return array(
-      'rebuild' => FALSE,
-      'rebuild_info' => array(),
-      'redirect' => NULL,
-      // @todo 'args' is usually set, so no other default 'build_info' keys are
-      //   appended via += $this->getFormStateDefaults().
-      'build_info' => array(
-        'args' => array(),
-        'files' => array(),
-      ),
-      'temporary' => array(),
-      'validation_complete' => FALSE,
-      'submitted' => FALSE,
-      'executed' => FALSE,
-      'programmed' => FALSE,
-      'programmed_bypass_access_check' => TRUE,
-      'cache'=> FALSE,
-      'method' => 'post',
-      'groups' => array(),
-      'buttons' => array(),
-      'errors' => array(),
-      'limit_validation_errors' => NULL,
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function rebuildForm($form_id, &$form_state, $old_form = NULL) {
+  public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form = NULL) {
     $form = $this->retrieveForm($form_id, $form_state);
 
     // If only parts of the form will be returned to the browser (e.g., Ajax or
@@ -335,7 +303,7 @@ public function rebuildForm($form_id, &$form_state, $old_form = NULL) {
 
     // Clear out all group associations as these might be different when
     // re-rendering the form.
-    $form_state['groups'] = array();
+    $form_state->set('groups', array());
 
     // Return a fully built form that is ready for rendering.
     return $this->doBuildForm($form_id, $form, $form_state);
@@ -344,13 +312,13 @@ public function rebuildForm($form_id, &$form_state, $old_form = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function getCache($form_build_id, &$form_state) {
+  public function getCache($form_build_id, FormStateInterface &$form_state) {
     if ($form = $this->keyValueExpirableFactory->get('form')->get($form_build_id)) {
       $user = $this->currentUser();
       if ((isset($form['#cache_token']) && $this->csrfToken->validate($form['#cache_token'])) || (!isset($form['#cache_token']) && $user->isAnonymous())) {
         if ($stored_form_state = $this->keyValueExpirableFactory->get('form_state')->get($form_build_id)) {
           // Re-populate $form_state for subsequent rebuilds.
-          $form_state = $stored_form_state + $form_state;
+          $form_state->setFormState($stored_form_state);
 
           // If the original form is contained in include files, load the files.
           // @see form_load_include()
@@ -380,7 +348,7 @@ public function getCache($form_build_id, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function setCache($form_build_id, $form, $form_state) {
+  public function setCache($form_build_id, $form, FormStateInterface $form_state) {
     // 6 hours cache life time for forms should be plenty.
     $expire = 21600;
 
@@ -393,77 +361,42 @@ public function setCache($form_build_id, $form, $form_state) {
     }
 
     // Cache form state.
-
     // Store the known list of safe strings for form re-use.
     // @todo Ensure we are not storing an excessively large string list in:
     //   https://www.drupal.org/node/2295823
-    $form_state['build_info']['safe_strings'] = SafeMarkup::getAll();
+    $form_state->addBuildInfo('safe_strings', SafeMarkup::getAll());
 
-    if ($data = array_diff_key($form_state, array_flip($this->getUncacheableKeys()))) {
+    if ($data = $form_state->getCacheableArray()) {
       $this->keyValueExpirableFactory->get('form_state')->setWithExpire($form_build_id, $data, $expire);
     }
   }
 
   /**
-   * Returns an array of $form_state keys that shouldn't be cached.
-   */
-  protected function getUncacheableKeys() {
-    return array(
-      // Public properties defined by form constructors and form handlers.
-      'always_process',
-      'must_validate',
-      'rebuild',
-      'rebuild_info',
-      'redirect',
-      'redirect_route',
-      'no_redirect',
-      'temporary',
-      // Internal properties defined by form processing.
-      'buttons',
-      'triggering_element',
-      'complete_form',
-      'groups',
-      'input',
-      'method',
-      'submit_handlers',
-      'validation_complete',
-      'submitted',
-      'executed',
-      'validate_handlers',
-      'values',
-      'errors',
-      'limit_validation_errors',
-    );
-  }
-
-  /**
    * {@inheritdoc}
    */
-  public function submitForm($form_arg, &$form_state) {
+  public function submitForm($form_arg, FormStateInterface &$form_state) {
     if (!isset($form_state['build_info']['args'])) {
       $args = func_get_args();
       // Remove $form and $form_state from the arguments.
       unset($args[0], $args[1]);
-      $form_state['build_info']['args'] = array_values($args);
+      $form_state->addBuildInfo('args', array_values($args));
     }
-    // Merge in default values.
-    $form_state += $this->getFormStateDefaults();
 
     // Populate $form_state['input'] with the submitted values before retrieving
     // the form, to be consistent with what self::buildForm() does for
     // non-programmatic submissions (form builder functions may expect it to be
     // there).
-    $form_state['input'] = $form_state['values'];
+    $form_state->set('input', $form_state->get('values'));
 
-    $form_state['programmed'] = TRUE;
+    $form_state->set('programmed', TRUE);
 
     $form_id = $this->getFormId($form_arg, $form_state);
     $form = $this->retrieveForm($form_id, $form_state);
     // Programmed forms are always submitted.
-    $form_state['submitted'] = TRUE;
+    $form_state->set('submitted', TRUE);
 
     // Reset form validation.
-    $form_state['must_validate'] = TRUE;
+    $form_state->set('must_validate', TRUE);
     $this->clearErrors($form_state);
 
     $this->prepareForm($form_id, $form, $form_state);
@@ -473,9 +406,9 @@ public function submitForm($form_arg, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function retrieveForm($form_id, &$form_state) {
+  public function retrieveForm($form_id, FormStateInterface &$form_state) {
     // Record the $form_id.
-    $form_state['build_info']['form_id'] = $form_id;
+    $form_state->addBuildInfo('form_id', $form_id);
 
     // We save two copies of the incoming arguments: one for modules to use
     // when mapping form ids to constructor functions, and another to pass to
@@ -513,20 +446,22 @@ public function retrieveForm($form_id, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function processForm($form_id, &$form, &$form_state) {
-    $form_state['values'] = array();
+  public function processForm($form_id, &$form, FormStateInterface &$form_state) {
+    $form_state->set('values', array());
 
     // With GET, these forms are always submitted if requested.
     if ($form_state['method'] == 'get' && !empty($form_state['always_process'])) {
-      if (!isset($form_state['input']['form_build_id'])) {
-        $form_state['input']['form_build_id'] = $form['#build_id'];
+      $input = $form_state->get('input');
+      if (!isset($input['form_build_id'])) {
+        $input['form_build_id'] = $form['#build_id'];
       }
-      if (!isset($form_state['input']['form_id'])) {
-        $form_state['input']['form_id'] = $form_id;
+      if (!isset($input['form_id'])) {
+        $input['form_id'] = $form_id;
       }
-      if (!isset($form_state['input']['form_token']) && isset($form['#token'])) {
-        $form_state['input']['form_token'] = $this->csrfToken->get($form['#token']);
+      if (!isset($input['form_token']) && isset($form['#token'])) {
+        $input['form_token'] = $this->csrfToken->get($form['#token']);
       }
+      $form_state->set('input', $input);
     }
 
     // self::doBuildForm() finishes building the form by calling element
@@ -550,7 +485,7 @@ public function processForm($form_id, &$form, &$form_state) {
       // exactly one submit button in the form, and if so, automatically use it
       // as triggering_element.
       if ($form_state['programmed'] && !isset($form_state['triggering_element']) && count($form_state['buttons']) == 1) {
-        $form_state['triggering_element'] = reset($form_state['buttons']);
+        $form_state->set('triggering_element', reset($form_state['buttons']));
       }
       $this->formValidator->validateForm($form_id, $form, $form_state);
 
@@ -594,7 +529,7 @@ public function processForm($form_id, &$form, &$form_state) {
         // Form building functions (e.g., self::handleInputElement()) may use
         // $form_state['rebuild'] to determine if they are running in the
         // context of a rebuild, so ensure it is set.
-        $form_state['rebuild'] = TRUE;
+        $form_state->setRebuild();
         $form = $this->rebuildForm($form_id, $form_state, $form);
       }
     }
@@ -614,14 +549,14 @@ public function processForm($form_id, &$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function prepareForm($form_id, &$form, &$form_state) {
+  public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
     $user = $this->currentUser();
 
     $form['#type'] = 'form';
-    $form_state['programmed'] = isset($form_state['programmed']) ? $form_state['programmed'] : FALSE;
+    $form_state->set('programmed', isset($form_state['programmed']) ? $form_state['programmed'] : FALSE);
 
     // Fix the form method, if it is 'get' in $form_state, but not in $form.
-    if ($form_state['method'] == 'get' && !isset($form['#method'])) {
+    if ($form_state->get('method') == 'get' && !isset($form['#method'])) {
       $form['#method'] = 'get';
     }
 
@@ -718,56 +653,56 @@ public function prepareForm($form_id, &$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm($form_id, &$form, &$form_state) {
+  public function validateForm($form_id, &$form, FormStateInterface &$form_state) {
     $this->formValidator->validateForm($form_id, $form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function redirectForm($form_state) {
+  public function redirectForm(FormStateInterface $form_state) {
     return $this->formSubmitter->redirectForm($form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function executeValidateHandlers(&$form, &$form_state) {
+  public function executeValidateHandlers(&$form, FormStateInterface &$form_state) {
     $this->formValidator->executeValidateHandlers($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function executeSubmitHandlers(&$form, &$form_state) {
+  public function executeSubmitHandlers(&$form, FormStateInterface &$form_state) {
     $this->formSubmitter->executeSubmitHandlers($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function doSubmitForm(&$form, &$form_state) {
+  public function doSubmitForm(&$form, FormStateInterface &$form_state) {
     throw new \LogicException('Use FormBuilderInterface::processForm() instead.');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setErrorByName($name, array &$form_state, $message = '') {
+  public function setErrorByName($name, FormStateInterface &$form_state, $message = '') {
     $this->formValidator->setErrorByName($name, $form_state, $message);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function clearErrors(array &$form_state) {
+  public function clearErrors(FormStateInterface &$form_state) {
     $this->formValidator->clearErrors($form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getErrors(array $form_state) {
+  public function getErrors(FormStateInterface &$form_state) {
     return $this->formValidator->getErrors($form_state);
   }
 
@@ -781,21 +716,21 @@ public function getAnyErrors() {
   /**
    * {@inheritdoc}
    */
-  public function getError($element, array &$form_state) {
+  public function getError($element, FormStateInterface &$form_state) {
     return $this->formValidator->getError($element, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setError(&$element, array &$form_state, $message = '') {
+  public function setError(&$element, FormStateInterface &$form_state, $message = '') {
     $this->formValidator->setError($element, $form_state, $message);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function doBuildForm($form_id, &$element, &$form_state) {
+  public function doBuildForm($form_id, &$element, FormStateInterface &$form_state) {
     // Initialize as unprocessed.
     $element['#processed'] = FALSE;
 
@@ -826,16 +761,16 @@ public function doBuildForm($form_id, &$element, &$form_state) {
       // Store a reference to the complete form in $form_state prior to building
       // the form. This allows advanced #process and #after_build callbacks to
       // perform changes elsewhere in the form.
-      $form_state['complete_form'] = &$element;
+      $form_state->setCompleteForm($element);
 
       // Set a flag if we have a correct form submission. This is always TRUE
       // for programmed forms coming from self::submitForm(), or if the form_id
       // coming from the POST data is set and matches the current form_id.
       if ($form_state['programmed'] || (!empty($form_state['input']) && (isset($form_state['input']['form_id']) && ($form_state['input']['form_id'] == $form_id)))) {
-        $form_state['process_input'] = TRUE;
+        $form_state->set('process_input', TRUE);
       }
       else {
-        $form_state['process_input'] = FALSE;
+        $form_state->set('process_input', FALSE);
       }
 
       // All form elements should have an #array_parents property.
@@ -931,7 +866,7 @@ public function doBuildForm($form_id, &$element, &$form_state) {
     // If there is a file element, we need to flip a flag so later the
     // form encoding can be set.
     if (isset($element['#type']) && $element['#type'] == 'file') {
-      $form_state['has_file_element'] = TRUE;
+      $form_state->set('has_file_element', TRUE);
     }
 
     // Final tasks for the form element after self::doBuildForm() has run for
@@ -949,26 +884,27 @@ public function doBuildForm($form_id, &$element, &$form_state) {
       // consistent as we can be across browsers, if no 'triggering_element' has
       // been identified yet, default it to the first button.
       if (!$form_state['programmed'] && !isset($form_state['triggering_element']) && !empty($form_state['buttons'])) {
-        $form_state['triggering_element'] = $form_state['buttons'][0];
+        $form_state->set('triggering_element', $form_state['buttons'][0]);
       }
 
+      $triggering_element = $form_state->get('triggering_element');
       // If the triggering element specifies "button-level" validation and
       // submit handlers to run instead of the default form-level ones, then add
       // those to the form state.
       foreach (array('validate', 'submit') as $type) {
-        if (isset($form_state['triggering_element']['#' . $type])) {
-          $form_state[$type . '_handlers'] = $form_state['triggering_element']['#' . $type];
+        if (isset($triggering_element['#' . $type])) {
+          $form_state->set($type . '_handlers', $triggering_element['#' . $type]);
         }
       }
 
       // If the triggering element executes submit handlers, then set the form
       // state key that's needed for those handlers to run.
-      if (!empty($form_state['triggering_element']['#executes_submit_callback'])) {
-        $form_state['submitted'] = TRUE;
+      if (!empty($triggering_element['#executes_submit_callback'])) {
+        $form_state->set('submitted', TRUE);
       }
 
       // Special processing if the triggering element is a button.
-      if (!empty($form_state['triggering_element']['#is_button'])) {
+      if (!empty($triggering_element['#is_button'])) {
         // Because there are several ways in which the triggering element could
         // have been determined (including from input variables set by
         // JavaScript or fallback behavior implemented for IE), and because
@@ -978,7 +914,7 @@ public function doBuildForm($form_id, &$element, &$form_state) {
         // $form_state['values'][BUTTON_NAME] being set. But it's common for
         // forms to have several buttons named 'op' and switch on
         // $form_state['values']['op'] during submit handler execution.
-        $form_state['values'][$form_state['triggering_element']['#name']] = $form_state['triggering_element']['#value'];
+        $form_state->addValue($triggering_element['#name'], $triggering_element['#value']);
       }
     }
     return $element;
@@ -987,7 +923,7 @@ public function doBuildForm($form_id, &$element, &$form_state) {
   /**
    * Adds the #name and #value properties of an input element before rendering.
    */
-  protected function handleInputElement($form_id, &$element, &$form_state) {
+  protected function handleInputElement($form_id, &$element, FormStateInterface &$form_state) {
     if (!isset($element['#name'])) {
       $name = array_shift($element['#parents']);
       $element['#name'] = $name;
@@ -1101,7 +1037,7 @@ protected function handleInputElement($form_id, &$element, &$form_state) {
     if ($process_input) {
       // Detect if the element triggered the submission via Ajax.
       if ($this->elementTriggeredScriptedSubmission($element, $form_state)) {
-        $form_state['triggering_element'] = $element;
+        $form_state->set('triggering_element', $element);
       }
 
       // If the form was submitted by the browser rather than via Ajax, then it
@@ -1113,16 +1049,18 @@ protected function handleInputElement($form_id, &$element, &$form_state) {
         // form_state_values_clean() and for the self::doBuildForm() code that
         // handles a form submission containing no button information in
         // \Drupal::request()->request.
-        $form_state['buttons'][] = $element;
+        $buttons = $form_state->get('buttons');
+        $buttons[] = $element;
+        $form_state->set('buttons', $buttons);
         if ($this->buttonWasClicked($element, $form_state)) {
-          $form_state['triggering_element'] = $element;
+          $form_state->set('triggering_element', $element);
         }
       }
     }
 
     // Set the element's value in $form_state['values'], but only, if its key
     // does not exist yet (a #value_callback may have already populated it).
-    if (!NestedArray::keyExists($form_state['values'], $element['#parents'])) {
+    if (!NestedArray::keyExists($form_state->getValues(), $element['#parents'])) {
       $this->setValue($element, $element['#value'], $form_state);
     }
   }
@@ -1138,7 +1076,7 @@ protected function handleInputElement($form_id, &$element, &$form_state) {
    * element value. An example where this is needed is if there are several
    * // buttons all named 'op', and only differing in their value.
    */
-  protected function elementTriggeredScriptedSubmission($element, &$form_state) {
+  protected function elementTriggeredScriptedSubmission($element, FormStateInterface &$form_state) {
     if (!empty($form_state['input']['_triggering_element_name']) && $element['#name'] == $form_state['input']['_triggering_element_name']) {
       if (empty($form_state['input']['_triggering_element_value']) || $form_state['input']['_triggering_element_value'] == $element['#value']) {
         return TRUE;
@@ -1167,7 +1105,7 @@ protected function elementTriggeredScriptedSubmission($element, &$form_state) {
    * to know which button was clicked should get that information from
    * $form_state['triggering_element'].
    */
-  protected function buttonWasClicked($element, &$form_state) {
+  protected function buttonWasClicked($element, FormStateInterface &$form_state) {
     // First detect normal 'vanilla' button clicks. Traditionally, all standard
     // buttons on a form share the same name (usually 'op'), and the specific
     // return value is used to determine which was clicked. This ONLY works as
@@ -1190,8 +1128,10 @@ protected function buttonWasClicked($element, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function setValue($element, $value, &$form_state) {
-    NestedArray::setValue($form_state['values'], $element['#parents'], $value, TRUE);
+  public function setValue($element, $value, FormStateInterface &$form_state) {
+    $values = $form_state->getValues();
+    NestedArray::setValue($values, $element['#parents'], $value, TRUE);
+    $form_state->set('values', $values);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Form/FormBuilderInterface.php b/core/lib/Drupal/Core/Form/FormBuilderInterface.php
index 6f42d14..bb4d953 100644
--- a/core/lib/Drupal/Core/Form/FormBuilderInterface.php
+++ b/core/lib/Drupal/Core/Form/FormBuilderInterface.php
@@ -17,13 +17,13 @@
    *
    * @param \Drupal\Core\Form\FormInterface|string $form_arg
    *   The value is identical to that of self::getForm()'s $form_arg argument.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return string
    *   The unique string identifying the desired form.
    */
-  public function getFormId($form_arg, &$form_state);
+  public function getFormId($form_arg, FormStateInterface &$form_state);
 
   /**
    * Gets a renderable form array.
@@ -58,164 +58,12 @@ public function getForm($form_arg);
    * previous page-load. The form is then passed on for processing, validation
    * and submission if there is proper input.
    *
-   * @param \Drupal\Core\Form\FormInterface|string $form_arg
+   * @param \Drupal\Core\Form\FormInterface|string $form_id
    *   The value must be one of the following:
    *   - The name of a class that implements \Drupal\Core\Form\FormInterface.
    *   - An instance of a class that implements \Drupal\Core\Form\FormInterface.
-   * @param array $form_state
-   *   An array which stores information about the form. This is passed as a
-   *   reference so that the caller can use it to examine what in the form
-   *   changed when the form submission process is complete. Furthermore, it may
-   *   be used to store information related to the processed data in the form,
-   *   which will persist across page requests when the 'cache' or 'rebuild'
-   *   flag is set. The following parameters may be set in $form_state to affect
-   *   how the form is rendered:
-   *   - build_info: Internal. An associative array of information stored by
-   *     Form API that is necessary to build and rebuild the form from cache
-   *     when the original context may no longer be available:
-   *     - callback: The actual callback to be used to retrieve the form array.
-   *       Can be any callable. If none is provided $form_id is used as the name
-   *       of a function to call instead.
-   *     - args: A list of arguments to pass to the form constructor.
-   *     - files: An optional array defining include files that need to be
-   *       loaded for building the form. Each array entry may be the path to a
-   *       file or another array containing values for the parameters 'type',
-   *       'module' and 'name' as needed by module_load_include(). The files
-   *       listed here are automatically loaded by form_get_cache(). By default
-   *       the current menu router item's 'file' definition is added, if any.
-   *       Use form_load_include() to add include files from a form constructor.
-   *     - form_id: Identification of the primary form being constructed and
-   *       processed.
-   *     - base_form_id: Identification for a base form, as declared in the form
-  *       class's \Drupal\Core\Form\BaseFormIdInterface::getBaseFormId() method.
-   *   - rebuild_info: Internal. Similar to 'build_info', but pertaining to
-   *     self::rebuildForm().
-   *   - rebuild: Normally, after the entire form processing is completed and
-   *     submit handlers have run, a form is considered to be done and
-   *     self::redirectForm() will redirect the user to a new page using a GET
-   *     request (so a browser refresh does not re-submit the form). However, if
-   *     'rebuild' has been set to TRUE, then a new copy of the form is
-   *     immediately built and sent to the browser, instead of a redirect. This
-   *     is used for multi-step forms, such as wizards and confirmation forms.
-   *     Normally, $form_state['rebuild'] is set by a submit handler, since its
-   *     is usually logic within a submit handler that determines whether a form
-   *     is done or requires another step. However, a validation handler may
-   *     already set $form_state['rebuild'] to cause the form processing to
-   *     bypass submit handlers and rebuild the form instead, even if there are
-   *     no validation errors.
-   *   - response: Used when a form needs to return some kind of a
-   *     \Symfony\Component\HttpFoundation\Response object, e.g., a
-   *     \Symfony\Component\HttpFoundation\BinaryFileResponse when triggering a
-   *     file download. If you use the $form_state['redirect'] key, it will be
-   *     used to build a \Symfony\Component\HttpFoundation\RedirectResponse and
-   *     will populate this key.
-   *   - redirect: Used to redirect the form on submission. It may either be a
-   *     string containing the destination URL, or an array of arguments
-   *     compatible with url(). See url() for complete information.
-   *   - no_redirect: If set to TRUE the form will NOT perform a redirect,
-   *     even if 'redirect' is set.
-   *   - method: The HTTP form method to use for finding the input for this
-   *     form. May be 'post' or 'get'. Defaults to 'post'. Note that 'get'
-   *     method forms do not use form ids so are always considered to be
-   *     submitted, which can have unexpected effects. The 'get' method should
-   *     only be used on forms that do not change data, as that is exclusively
-   *     the domain of 'post.'
-   *   - cache: If set to TRUE the original, unprocessed form structure will be
-   *     cached, which allows the entire form to be rebuilt from cache. A
-   *     typical form workflow involves two page requests; first, a form is
-   *     built and rendered for the user to fill in. Then, the user fills the
-   *     form in and submits it, triggering a second page request in which the
-   *     form must be built and processed. By default, $form and $form_state are
-   *     built from scratch during each of these page requests. Often, it is
-   *     necessary or desired to persist the $form and $form_state variables
-   *     from the initial page request to the one that processes the submission.
-   *     'cache' can be set to TRUE to do this. A prominent example is an
-   *     Ajax-enabled form, in which ajax_process_form() enables form caching
-   *     for all forms that include an element with the #ajax property. (The
-   *     Ajax handler has no way to build the form itself, so must rely on the
-   *     cached version.) Note that the persistence of $form and $form_state
-   *     happens automatically for (multi-step) forms having the 'rebuild' flag
-   *     set, regardless of the value for 'cache'.
-   *   - no_cache: If set to TRUE the form will NOT be cached, even if 'cache'
-   *     is set.
-   *   - values: An associative array of values submitted to the form. The
-   *     validation functions and submit functions use this array for nearly all
-   *     their decision making. (Note that #tree determines whether the values
-   *     are a flat array or an array whose structure parallels the $form array.
-   *     See the @link forms_api_reference.html Form API reference @endlink for
-   *     more information.)
-   *   - input: The array of values as they were submitted by the user. These
-   *     are raw and unvalidated, so should not be used without a thorough
-   *     understanding of security implications. In almost all cases, code
-   *     should use the data in the 'values' array exclusively. The most common
-   *     use of this key is for multi-step forms that need to clear some of the
-   *     user input when setting 'rebuild'. The values correspond to
-   *     \Drupal::request()->request or \Drupal::request()->query, depending on
-   *     the 'method' chosen.
-   *   - always_process: If TRUE and the method is GET, a form_id is not
-   *     necessary. This should only be used on RESTful GET forms that do NOT
-   *     write data, as this could lead to security issues. It is useful so that
-   *     searches do not need to have a form_id in their query arguments to
-   *     trigger the search.
-   *   - must_validate: Ordinarily, a form is only validated once, but there are
-   *     times when a form is resubmitted internally and should be validated
-   *     again. Setting this to TRUE will force that to happen. This is most
-   *     likely to occur during Ajax operations.
-   *   - programmed: If TRUE, the form was submitted programmatically, usually
-   *     invoked via self::submitForm(). Defaults to FALSE.
-   *   - programmed_bypass_access_check: If TRUE, programmatic form submissions
-   *     are processed without taking #access into account. Set this to FALSE
-   *     when submitting a form programmatically with values that may have been
-   *     input by the user executing the current request; this will cause
-   *     #access to be respected as it would on a normal form submission.
-   *     Defaults to TRUE.
-   *   - process_input: Boolean flag. TRUE signifies correct form submission.
-   *     This is always TRUE for programmed forms coming from self::submitForm()
-   *     (see 'programmed' key), or if the form_id coming from the
-   *     \Drupal::request()->request data is set and matches the current form_id.
-   *   - submitted: If TRUE, the form has been submitted. Defaults to FALSE.
-   *   - executed: If TRUE, the form was submitted and has been processed and
-   *     executed. Defaults to FALSE.
-   *   - triggering_element: (read-only) The form element that triggered
-   *     submission, which may or may not be a button (in the case of Ajax
-   *     forms). This key is often used to distinguish between various buttons
-   *     in a submit handler, and is also used in Ajax handlers.
-   *   - has_file_element: Internal. If TRUE, there is a file element and Form
-   *     API will set the appropriate 'enctype' HTML attribute on the form.
-   *   - groups: Internal. An array containing references to details elements to
-   *     render them within vertical tabs.
-   *   - storage: $form_state['storage'] is not a special key, and no specific
-   *     support is provided for it in the Form API. By tradition it was
-   *     the location where application-specific data was stored for
-   *     communication between the submit, validation, and form builder
-   *     functions, especially in a multi-step-style form. Form implementations
-   *     may use any key(s) within $form_state (other than the keys listed here
-   *     and other reserved ones used by Form API internals) for this kind of
-   *     storage. The recommended way to ensure that the chosen key doesn't
-   *     conflict with ones used by the Form API or other modules is to use the
-   *     module name as the key name or a prefix for the key name. For example,
-   *     the entity form classes use $this->entity in entity forms,
-   *     or $form_state['controller']->getEntity() outside the controller, to
-   *     store information about the entity being edited, and this information
-   *     stays available across successive clicks of the "Preview" button (if
-   *     available) as well as when the "Save" button is finally clicked.
-   *   - buttons: A list containing copies of all submit and button elements in
-   *     the form.
-   *   - complete_form: A reference to the $form variable containing the
-   *     complete form structure. #process, #after_build, #element_validate, and
-   *     other handlers being invoked on a form element may use this reference
-   *     to access other information in the form the element is contained in.
-   *   - temporary: An array holding temporary data accessible during the
-   *     current page request only. All $form_state properties that are not
-   *     reserved keys (see form_state_keys_no_cache()) persist throughout a
-   *     multistep form sequence. Form API provides this key for modules to
-   *     communicate information across form-related functions during a single
-   *     page request. It may be used to temporarily save data that does not
-   *     need to or should not be cached during the whole form workflow; e.g.,
-   *     data that needs to be accessed during the current form build process
-   *     only. There is no use-case for this functionality in Drupal core.
-   *   Information on how certain $form_state properties control redirection
-   *   behavior after form submission may be found in self::redirectForm().
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The rendered form. This function may also perform a redirect and hence
@@ -223,12 +71,7 @@ public function getForm($form_arg);
    *
    * @see self::redirectForm()
    */
-  public function buildForm($form_id, array &$form_state);
-
-  /**
-   * Retrieves default values for the $form_state array.
-   */
-  public function getFormStateDefaults();
+  public function buildForm($form_id, FormStateInterface &$form_state);
 
   /**
    * Constructs a new $form from the information in $form_state.
@@ -249,8 +92,8 @@ public function getFormStateDefaults();
    * @param string $form_id
    *   The unique string identifying the desired form. If a function with that
    *   name exists, it is called to build the form array.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param array|null $old_form
    *   (optional) A previously built $form. Used to retain the #build_id and
    *   #action properties in Ajax callbacks and similar partial form rebuilds.
@@ -266,17 +109,17 @@ public function getFormStateDefaults();
    * @see self::processForm()
    * @see \Drupal\system\FormAjaxController::content()
    */
-  public function rebuildForm($form_id, &$form_state, $old_form = NULL);
+  public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form = NULL);
 
   /**
    * Fetches a form from the cache.
    */
-  public function getCache($form_build_id, &$form_state);
+  public function getCache($form_build_id, FormStateInterface &$form_state);
 
   /**
    * Stores a form in the cache.
    */
-  public function setCache($form_build_id, $form, $form_state);
+  public function setCache($form_build_id, $form, FormStateInterface $form_state);
 
   /**
    * Retrieves, populates, and processes a form.
@@ -293,8 +136,8 @@ public function setCache($form_build_id, $form, $form_state);
    *   the desired form. If $form_arg is a string and a function with that
    *   name exists, it is called to build the form array.
    * @param $form_state
-   *   A keyed array containing the current state of the form. Most important is
-   *   the $form_state['values'] collection, a tree of data used to simulate the
+   *   The current state of the form. Most important is the
+   *   $form_state['values'] collection, a tree of data used to simulate the
    *   incoming \Drupal::request()->request information from a user's form
    *   submission. If a key is not filled in $form_state['values'], then the
    *   default value of the respective element is used. To submit an unchecked
@@ -310,7 +153,7 @@ public function setCache($form_build_id, $form, $form_state);
    *   $form_state build info array so that the reference can be preserved. For
    *   example, a form builder function with the following signature:
    *   @code
-   *   function mymodule_form($form, &$form_state, &$object) {
+   *   function mymodule_form($form, FormStateInterface &$form_state, &$object) {
    *   }
    *   @endcode
    *   would be called via self::submitForm() as follows:
@@ -322,7 +165,7 @@ public function setCache($form_build_id, $form, $form_state);
    * For example:
    * @code
    * // register a new user
-   * $form_state = array();
+   * $form_state = new FormState();
    * $form_state['values']['name'] = 'robo-user';
    * $form_state['values']['mail'] = 'robouser@example.com';
    * $form_state['values']['pass']['pass1'] = 'password';
@@ -331,7 +174,7 @@ public function setCache($form_build_id, $form, $form_state);
    * drupal_form_submit('user_register_form', $form_state);
    * @endcode
    */
-  public function submitForm($form_arg, &$form_state);
+  public function submitForm($form_arg, FormStateInterface &$form_state);
 
   /**
    * Retrieves the structured array that defines a given form.
@@ -339,14 +182,14 @@ public function submitForm($form_arg, &$form_state);
    * @param string $form_id
    *   The unique string identifying the desired form. If a function
    *   with that name exists, it is called to build the form array.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form, including the
-   *   additional arguments to self::getForm() or self::submitForm() in the
-   *   'args' component of the array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form, including the additional arguments to
+   *   self::getForm() or self::submitForm() in the 'args' component of the
+   *   array.
    *
    * @return mixed|\Symfony\Component\HttpFoundation\Response
    */
-  public function retrieveForm($form_id, &$form_state);
+  public function retrieveForm($form_id, FormStateInterface &$form_state);
 
   /**
    * Processes a form submission.
@@ -358,16 +201,15 @@ public function retrieveForm($form_id, &$form_state);
    *   The unique string identifying the current form.
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form. This
-   *   includes the current persistent storage data for the form, and
-   *   any data passed along by earlier steps when displaying a
-   *   multi-step form. Additional information, like the sanitized
-   *   \Drupal::request()->request data, is also accumulated here.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form. This includes the current persistent
+   *   storage data for the form, and any data passed along by earlier steps
+   *   when displaying a multi-step form. Additional information, like the
+   *   sanitized \Drupal::request()->request data, is also accumulated here.
    *
    * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
    */
-  public function processForm($form_id, &$form, &$form_state);
+  public function processForm($form_id, &$form, FormStateInterface &$form_state);
 
   /**
    * Prepares a structured form array.
@@ -380,11 +222,11 @@ public function processForm($form_id, &$form, &$form_state);
    *   theming, and hook_form_alter functions.
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form. Passed
-   *   in here so that hook_form_alter() calls can use it, as well.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form. Passed in here so that hook_form_alter()
+   *   calls can use it, as well.
    */
-  public function prepareForm($form_id, &$form, &$form_state);
+  public function prepareForm($form_id, &$form, FormStateInterface &$form_state);
 
   /**
    * Builds and processes all elements in the structured form array.
@@ -473,15 +315,14 @@ public function prepareForm($form_id, &$form, &$form_state);
    *   theming, and hook_form_alter functions.
    * @param array $element
    *   An associative array containing the structure of the current element.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form. In this
-   *   context, it is used to accumulate information about which button
-   *   was clicked when the form was submitted, as well as the sanitized
-   *   \Drupal::request()->request data.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form. In this context, it is used to accumulate
+   *   information about which button was clicked when the form was submitted,
+   *   as well as the sanitized \Drupal::request()->request data.
    *
    * @return array
    */
-  public function doBuildForm($form_id, &$element, &$form_state);
+  public function doBuildForm($form_id, &$element, FormStateInterface &$form_state);
 
   /**
    * Changes submitted form values during form validation.
@@ -508,8 +349,8 @@ public function doBuildForm($form_id, &$element, &$form_state);
    * @param $value
    *   The new value for the form element.
    * @param $form_state
-   *   Form state array where the value change should be recorded.
+   *   The current state of the form where the value change should be recorded.
    */
-  public function setValue($element, $value, &$form_state);
+  public function setValue($element, $value, FormStateInterface &$form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Form/FormErrorInterface.php b/core/lib/Drupal/Core/Form/FormErrorInterface.php
index 43d0c5a..825ff49 100644
--- a/core/lib/Drupal/Core/Form/FormErrorInterface.php
+++ b/core/lib/Drupal/Core/Form/FormErrorInterface.php
@@ -9,6 +9,9 @@
 
 /**
  * Provides an interface for form error handling.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ *   Use \Drupal\Core\Form\FormStateInterface directly.
  */
 interface FormErrorInterface {
 
@@ -99,8 +102,8 @@
    *   element is array('foo', 'bar', 'baz') then you may set an error on 'foo'
    *   or 'foo][bar][baz'. Setting an error on 'foo' sets an error for every
    *   element where the #parents array starts with 'foo'.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $message
    *   (optional) The error message to present to the user.
    *
@@ -108,26 +111,26 @@
    *   Return value is for internal use only. To get a list of errors, use
    *   FormErrorInterface::getErrors() or FormErrorInterface::getError().
    */
-  public function setErrorByName($name, array &$form_state, $message = '');
+  public function setErrorByName($name, FormStateInterface &$form_state, $message = '');
 
   /**
    * Clears all errors against all form elements made by FormErrorInterface::setErrorByName().
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function clearErrors(array &$form_state);
+  public function clearErrors(FormStateInterface &$form_state);
 
   /**
    * Returns an associative array of all errors.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   An array of all errors, keyed by the name of the form element.
    */
-  public function getErrors(array $form_state);
+  public function getErrors(FormStateInterface &$form_state);
 
   /**
    * Returns the error message filed against the given form element.
@@ -137,18 +140,18 @@ public function getErrors(array $form_state);
    *
    * @param array $element
    *   The form element to check for errors.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return string|null
    *   Either the error message for this element or NULL if there are no errors.
    */
-  public function getError($element, array &$form_state);
+  public function getError($element, FormStateInterface &$form_state);
 
   /**
    * Flags an element as having an error.
    */
-  public function setError(&$element, array &$form_state, $message = '');
+  public function setError(&$element, FormStateInterface &$form_state, $message = '');
 
   /**
    * Returns if there have been any errors during build.
diff --git a/core/lib/Drupal/Core/Form/FormInterface.php b/core/lib/Drupal/Core/Form/FormInterface.php
index 40daf12..00c686e 100644
--- a/core/lib/Drupal/Core/Form/FormInterface.php
+++ b/core/lib/Drupal/Core/Form/FormInterface.php
@@ -27,32 +27,32 @@ public function getFormId();
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The form structure.
    */
-  public function buildForm(array $form, array &$form_state);
+  public function buildForm(array $form, FormStateInterface $form_state);
 
   /**
    * Form validation handler.
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function validateForm(array &$form, array &$form_state);
+  public function validateForm(array &$form, FormStateInterface $form_state);
 
   /**
    * Form submission handler.
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function submitForm(array &$form, array &$form_state);
+  public function submitForm(array &$form, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Form/FormState.php b/core/lib/Drupal/Core/Form/FormState.php
new file mode 100644
index 0000000..b0a21db
--- /dev/null
+++ b/core/lib/Drupal/Core/Form/FormState.php
@@ -0,0 +1,748 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Form\FormState.
+ */
+
+namespace Drupal\Core\Form;
+
+use Drupal\Core\Url;
+
+/**
+ * Stores information about the state of a form.
+ *
+ * @todo Remove usage of \ArrayAccess in https://www.drupal.org/node/2310255.
+ */
+class FormState implements FormStateInterface, \ArrayAccess {
+
+  /**
+   * Tracks if any errors have been set on any form.
+   *
+   * @var bool
+   */
+  protected static $anyErrors = FALSE;
+
+  /**
+   * The internal storage of the form state.
+   *
+   * @var array
+   */
+  protected $internalStorage = array();
+
+  /**
+   * The complete form structure.
+   *
+   * #process, #after_build, #element_validate, and other handlers being invoked
+   * on a form element may use this reference to access other information in the
+   * form the element is contained in.
+   *
+   * @see self::getCompleteForm()
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $complete_form;
+
+  /**
+   * An associative array of information stored by Form API that is necessary to
+   * build and rebuild the form from cache when the original context may no
+   * longer be available:
+   *   - callback: The actual callback to be used to retrieve the form array.
+   *     Can be any callable. If none is provided $form_id is used as the name
+   *     of a function to call instead.
+   *   - args: A list of arguments to pass to the form constructor.
+   *   - files: An optional array defining include files that need to be loaded
+   *     for building the form. Each array entry may be the path to a file or
+   *     another array containing values for the parameters 'type', 'module' and
+   *     'name' as needed by module_load_include(). The files listed here are
+   *     automatically loaded by form_get_cache(). By default the current menu
+   *     router item's 'file' definition is added, if any. Use
+   *     form_load_include() to add include files from a form constructor.
+   *   - form_id: Identification of the primary form being constructed and
+   *     processed.
+   *   - base_form_id: Identification for a base form, as declared in the form
+   *     class's \Drupal\Core\Form\BaseFormIdInterface::getBaseFormId() method.
+   *
+   * @var array
+   */
+  protected $build_info = array(
+    'args' => array(),
+    'files' => array(),
+  );
+
+  /**
+   * Similar to self::$build_info, but pertaining to
+   * \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $rebuild_info = array();
+
+  /**
+   * Normally, after the entire form processing is completed and submit handlers
+   * have run, a form is considered to be done and
+   * \Drupal\Core\Form\FormSubmitterInterface::redirectForm() will redirect the
+   * user to a new page using a GET request (so a browser refresh does not
+   * re-submit the form). However, if 'rebuild' has been set to TRUE, then a new
+   * copy of the form is immediately built and sent to the browser, instead of a
+   * redirect. This is used for multi-step forms, such as wizards and
+   * confirmation forms. Normally, $form_state['rebuild'] is set by a submit
+   * handler, since its is usually logic within a submit handler that determines
+   * whether a form is done or requires another step. However, a validation
+   * handler may already set $form_state['rebuild'] to cause the form processing
+   * to bypass submit handlers and rebuild the form instead, even if there are
+   * no validation errors.
+   *
+   * This property is uncacheable.
+   *
+   * @see self::setRebuild()
+   *
+   * @var bool
+   */
+  protected $rebuild = FALSE;
+
+  /**
+   * Used when a form needs to return some kind of a
+   * \Symfony\Component\HttpFoundation\Response object, e.g., a
+   * \Symfony\Component\HttpFoundation\BinaryFileResponse when triggering a
+   * file download. If you use the $form_state['redirect'] key, it will be used
+   * to build a \Symfony\Component\HttpFoundation\RedirectResponse and will
+   * populate this key.
+   *
+   * @var \Symfony\Component\HttpFoundation\Response|null
+   */
+  protected $response;
+
+  /**
+   * Used to redirect the form on submission. It may either be a  string
+   * containing the destination URL, or an array of arguments compatible with
+   * url(). See url() for complete information.
+   *
+   * This property is uncacheable.
+   *
+   * @var string|array|null
+   */
+  protected $redirect;
+
+  /**
+   * Used for route-based redirects.
+   *
+   * This property is uncacheable.
+   *
+   * @var \Drupal\Core\Url|array
+   */
+  protected $redirect_route;
+
+  /**
+   * If set to TRUE the form will NOT perform a redirect, even if
+   * self::$redirect is set.
+   *
+   * This property is uncacheable.
+   *
+   * @var bool
+   */
+  protected $no_redirect;
+
+  /**
+   * The HTTP form method to use for finding the input for this form.
+   *
+   * May be 'post' or 'get'. Defaults to 'post'. Note that 'get' method forms do
+   * not use form ids so are always considered to be submitted, which can have
+   * unexpected effects. The 'get' method should only be used on forms that do
+   * not change data, as that is exclusively the domain of 'post.'
+   *
+   * This property is uncacheable.
+   *
+   * @var string
+   */
+  protected $method = 'post';
+
+  /**
+   * If set to TRUE the original, unprocessed form structure will be cached,
+   * which allows the entire form to be rebuilt from cache. A typical form
+   * workflow involves two page requests; first, a form is built and rendered
+   * for the user to fill in. Then, the user fills the form in and submits it,
+   * triggering a second page request in which the form must be built and
+   * processed. By default, $form and $form_state are built from scratch during
+   * each of these page requests. Often, it is necessary or desired to persist
+   * the $form and $form_state variables from the initial page request to the
+   * one that processes the submission. 'cache' can be set to TRUE to do this.
+   * A prominent example is an Ajax-enabled form, in which ajax_process_form()
+   * enables form caching for all forms that include an element with the #ajax
+   * property. (The Ajax handler has no way to build the form itself, so must
+   * rely on the cached version.) Note that the persistence of $form and
+   * $form_state happens automatically for (multi-step) forms having the
+   * self::$rebuild flag set, regardless of the value for self::$cache.
+   *
+   * @var bool
+   */
+  protected $cache = FALSE;
+
+  /**
+   * If set to TRUE the form will NOT be cached, even if 'cache' is set.
+   *
+   * @var bool
+   */
+  protected $no_cache;
+
+  /**
+   * An associative array of values submitted to the form.
+   *
+   * The validation functions and submit functions use this array for nearly all
+   * their decision making. (Note that #tree determines whether the values are a
+   * flat array or an array whose structure parallels the $form array. See the
+   * @link forms_api_reference.html Form API reference @endlink for more
+   * information.)
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $values;
+
+  /**
+   * The array of values as they were submitted by the user.
+   *
+   * These are raw and unvalidated, so should not be used without a thorough
+   * understanding of security implications. In almost all cases, code should
+   * use the data in the 'values' array exclusively. The most common use of this
+   * key is for multi-step forms that need to clear some of the user input when
+   * setting 'rebuild'. The values correspond to \Drupal::request()->request or
+   * \Drupal::request()->query, depending on the 'method' chosen.
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $input;
+
+  /**
+   * If TRUE and the method is GET, a form_id is not necessary.
+   *
+   * This should only be used on RESTful GET forms that do NOT write data, as
+   * this could lead to security issues. It is useful so that searches do not
+   * need to have a form_id in their query arguments to trigger the search.
+   *
+   * This property is uncacheable.
+   *
+   * @var bool
+   */
+  protected $always_process;
+
+  /**
+   * Ordinarily, a form is only validated once, but there are times when a form
+   * is resubmitted internally and should be validated again. Setting this to
+   * TRUE will force that to happen. This is most likely to occur during Ajax
+   * operations.
+   *
+   * This property is uncacheable.
+   *
+   * @var bool
+   */
+  protected $must_validate;
+
+  /**
+   * If TRUE, the form was submitted programmatically, usually invoked via
+   * \Drupal\Core\Form\FormBuilderInterface::submitForm(). Defaults to FALSE.
+   *
+   * @var bool
+   */
+  protected $programmed = FALSE;
+
+  /**
+   * If TRUE, programmatic form submissions are processed without taking #access
+   * into account. Set this to FALSE when submitting a form programmatically
+   * with values that may have been input by the user executing the current
+   * request; this will cause #access to be respected as it would on a normal
+   * form submission. Defaults to TRUE.
+   *
+   * @var bool
+   */
+  protected $programmed_bypass_access_check = TRUE;
+
+  /**
+   * TRUE signifies correct form submission. This is always TRUE for programmed
+   * forms coming from \Drupal\Core\Form\FormBuilderInterface::submitForm() (see
+   * 'programmed' key), or if the form_id coming from the
+   * \Drupal::request()->request data is set and matches the current form_id.
+   *
+   * @var bool
+   */
+  protected $process_input;
+
+  /**
+   * If TRUE, the form has been submitted. Defaults to FALSE.
+   *
+   * This property is uncacheable.
+   *
+   * @var bool
+   */
+  protected $submitted = FALSE;
+
+  /**
+   * If TRUE, the form was submitted and has been processed and executed.
+   *
+   * This property is uncacheable.
+   *
+   * @var bool
+   */
+  protected $executed = FALSE;
+
+  /**
+   * The form element that triggered submission, which may or may not be a
+   * button (in the case of Ajax forms). This key is often used to distinguish
+   * between various buttons in a submit handler, and is also used in Ajax
+   * handlers.
+   *
+   * This property is uncacheable.
+   *
+   * @var array|null
+   */
+  protected $triggering_element;
+
+  /**
+   * If TRUE, there is a file element and Form API will set the appropriate
+   * 'enctype' HTML attribute on the form.
+   *
+   * @var bool
+   */
+  protected $has_file_element;
+
+  /**
+   * Contains references to details elements to render them within vertical tabs.
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $groups = array();
+
+  /**
+   *  This is not a special key, and no specific support is provided for it in
+   *  the Form API. By tradition it was the location where application-specific
+   *  data was stored for communication between the submit, validation, and form
+   *  builder functions, especially in a multi-step-style form. Form
+   *  implementations may use any key(s) within $form_state (other than the keys
+   *  listed here and other reserved ones used by Form API internals) for this
+   *  kind of storage. The recommended way to ensure that the chosen key doesn't
+   *  conflict with ones used by the Form API or other modules is to use the
+   *  module name as the key name or a prefix for the key name. For example, the
+   *  entity form classes use $this->entity in entity forms, or
+   *  $form_state['controller']->getEntity() outside the controller, to store
+   *  information about the entity being edited, and this information stays
+   *  available across successive clicks of the "Preview" button (if available)
+   *  as well as when the "Save" button is finally clicked.
+   *
+   * @var array
+   */
+  protected $storage = array();
+
+  /**
+   * A list containing copies of all submit and button elements in the form.
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $buttons = array();
+
+  /**
+   * Holds temporary data accessible during the current page request only.
+   *
+   * All $form_state properties that are not reserved keys (see
+   * other properties marked as uncacheable) persist throughout a multistep form
+   * sequence. Form API provides this key for modules to communicate information
+   * across form-related functions during a single page request. It may be used
+   * to temporarily save data that does not need to or should not be cached
+   * during the whole form workflow; e.g., data that needs to be accessed during
+   * the current form build process only. There is no use-case for this
+   * functionality in Drupal core.
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $temporary;
+
+  /**
+   * Tracks if the form has finished validation.
+   *
+   * This property is uncacheable.
+   *
+   * @var bool
+   */
+  protected $validation_complete = FALSE;
+
+  /**
+   * Contains errors for this form.
+   *
+   * This property is uncacheable.
+   *
+   * @var array
+   */
+  protected $errors = array();
+
+  /**
+   * Stores which errors should be limited during validation.
+   *
+   * This property is uncacheable.
+   *
+   * @var array|null
+   */
+  protected $limit_validation_errors;
+
+  /**
+   * Stores the gathered validation handlers.
+   *
+   * This property is uncacheable.
+   *
+   * @var array|null
+   */
+  protected $validate_handlers;
+
+  /**
+   * Stores the gathered submission handlers.
+   *
+   * This property is uncacheable.
+   *
+   * @var array|null
+   */
+  protected $submit_handlers;
+
+  /**
+   * Constructs a \Drupal\Core\Form\FormState object.
+   *
+   * @param array $form_state_additions
+   *   (optional) An associative array used to build the current state of the
+   *   form. Use this to pass additional information to the form, such as the
+   *   langcode. Defaults to an empty array.
+   */
+  public function __construct(array $form_state_additions = array()) {
+    $this->setFormState($form_state_additions);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setFormState(array $form_state_additions) {
+    foreach ($form_state_additions as $key => $value) {
+      $this->set($key, $value);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheableArray($allowed_keys = array()) {
+    $cacheable_array = array(
+      'build_info' => $this->build_info,
+      'response' => $this->response,
+      'cache' => $this->cache,
+      'no_cache' => $this->no_cache,
+      'programmed' => $this->programmed,
+      'programmed_bypass_access_check' => $this->programmed_bypass_access_check,
+      'process_input' => $this->process_input,
+      'has_file_element' => $this->has_file_element,
+      'storage' => $this->storage,
+    ) + $this->internalStorage;
+    foreach ($allowed_keys as $allowed_key) {
+      $cacheable_array[$allowed_key] = $this->get($allowed_key);
+    }
+    return $cacheable_array;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setCompleteForm(array &$complete_form) {
+    $this->complete_form = &$complete_form;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function &getCompleteForm() {
+    return $this->complete_form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function offsetExists($offset) {
+    return isset($this->{$offset}) || isset($this->internalStorage[$offset]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function &offsetGet($offset) {
+    $value = &$this->get($offset);
+    return $value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function offsetSet($offset, $value) {
+    $this->set($offset, $value);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function offsetUnset($offset) {
+    if (property_exists($this, $offset)) {
+      $this->{$offset} = NULL;
+    }
+    unset($this->internalStorage[$offset]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setIfNotExists($property, $value) {
+    if (!$this->has($property)) {
+      $this->set($property, $value);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function &get($property) {
+    if (property_exists($this, $property)) {
+      return $this->{$property};
+    }
+    else {
+      if (!isset($this->internalStorage[$property])) {
+        $this->internalStorage[$property] = NULL;
+      }
+      return $this->internalStorage[$property];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($property, $value) {
+    if (property_exists($this, $property)) {
+      $this->{$property} = $value;
+    }
+    else {
+      $this->internalStorage[$property] = $value;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function has($property) {
+    if (property_exists($this, $property)) {
+      return $this->{$property} !== NULL;
+    }
+
+    return array_key_exists($property, $this->internalStorage);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addBuildInfo($property, $value) {
+    $build_info = $this->get('build_info');
+    $build_info[$property] = $value;
+    $this->set('build_info', $build_info);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValues() {
+    return $this->values;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addValue($property, $value) {
+    $values = $this->getValues();
+    $values[$property] = $value;
+    $this->set('values', $values);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setRedirect(Url $url) {
+    $this->set('redirect_route', $url);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirect() {
+    // Skip redirection for form submissions invoked via
+    // \Drupal\Core\Form\FormBuilderInterface::submitForm().
+    if ($this->get('programmed')) {
+      return FALSE;
+    }
+    // Skip redirection if rebuild is activated.
+    if ($this->get('rebuild')) {
+      return FALSE;
+    }
+    // Skip redirection if it was explicitly disallowed.
+    if ($this->get('no_redirect')) {
+      return FALSE;
+    }
+
+    // Check for a route-based redirection.
+    if ($redirect_route = $this->get('redirect_route')) {
+      // @todo Remove once all redirects are converted to \Drupal\Core\Url. See
+      //   https://www.drupal.org/node/2189661.
+      if (!($redirect_route instanceof Url)) {
+        $redirect_route += array(
+          'route_parameters' => array(),
+          'options' => array(),
+        );
+        $redirect_route = new Url($redirect_route['route_name'], $redirect_route['route_parameters'], $redirect_route['options']);
+      }
+
+      $redirect_route->setAbsolute();
+      return $redirect_route;
+    }
+
+    return $this->get('redirect');
+  }
+
+  /**
+   * Sets the global status of errors.
+   *
+   * @param bool $errors
+   *   TRUE if any form has any errors, FALSE otherwise.
+   */
+  protected static function setAnyErrors($errors = TRUE) {
+    static::$anyErrors = $errors;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function hasAnyErrors() {
+    return static::$anyErrors;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setErrorByName($name, $message = '') {
+    if ($this->get('validation_complete')) {
+      throw new \LogicException('Form errors cannot be set after form validation has finished.');
+    }
+
+    $errors = $this->getErrors();
+    if (!isset($errors[$name])) {
+      $record = TRUE;
+      $limit_validation_errors = $this->get('limit_validation_errors');
+      if ($limit_validation_errors !== NULL) {
+        // #limit_validation_errors is an array of "sections" within which user
+        // input must be valid. If the element is within one of these sections,
+        // the error must be recorded. Otherwise, it can be suppressed.
+        // #limit_validation_errors can be an empty array, in which case all
+        // errors are suppressed. For example, a "Previous" button might want
+        // its submit action to be triggered even if none of the submitted
+        // values are valid.
+        $record = FALSE;
+        foreach ($limit_validation_errors as $section) {
+          // Exploding by '][' reconstructs the element's #parents. If the
+          // reconstructed #parents begin with the same keys as the specified
+          // section, then the element's values are within the part of
+          // $form_state['values'] that the clicked button requires to be valid,
+          // so errors for this element must be recorded. As the exploded array
+          // will all be strings, we need to cast every value of the section
+          // array to string.
+          if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
+            $record = TRUE;
+            break;
+          }
+        }
+      }
+      if ($record) {
+        $errors[$name] = $message;
+        $this->set('errors', $errors);
+        static::setAnyErrors();
+        if ($message) {
+          $this->drupalSetMessage($message, 'error');
+        }
+      }
+    }
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setError(&$element, $message = '') {
+    $this->setErrorByName(implode('][', $element['#parents']), $message);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clearErrors() {
+    $this->set('errors', array());
+    static::setAnyErrors(FALSE);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getError($element) {
+    if ($errors = $this->getErrors($this)) {
+      $parents = array();
+      foreach ($element['#parents'] as $parent) {
+        $parents[] = $parent;
+        $key = implode('][', $parents);
+        if (isset($errors[$key])) {
+          return $errors[$key];
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getErrors() {
+    return $this->get('errors');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setRebuild($rebuild = TRUE) {
+    $this->set('rebuild', $rebuild);
+    return $this;
+  }
+
+  /**
+   * Wraps drupal_set_message().
+   *
+   * @return array|null
+   */
+  protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) {
+    return drupal_set_message($message, $type, $repeat);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Form/FormErrorInterface.php b/core/lib/Drupal/Core/Form/FormStateInterface.php
similarity index 53%
copy from core/lib/Drupal/Core/Form/FormErrorInterface.php
copy to core/lib/Drupal/Core/Form/FormStateInterface.php
index 43d0c5a..24ceb52 100644
--- a/core/lib/Drupal/Core/Form/FormErrorInterface.php
+++ b/core/lib/Drupal/Core/Form/FormStateInterface.php
@@ -2,15 +2,171 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Form\FormErrorInterface.
+ * Contains \Drupal\Core\Form\FormStateInterface.
  */
 
 namespace Drupal\Core\Form;
 
+use Drupal\Core\Url;
+
 /**
- * Provides an interface for form error handling.
+ * Provides an interface for an object containing the current state of a form.
+ *
+ * This is passed to all form related code so that the caller can use it to
+ * examine what in the form changed when the form submission process is
+ * complete. Furthermore, it may be used to store information related to the
+ * processed data in the form, which will persist across page requests when the
+ * 'cache' or 'rebuild' flag is set. See
+ * \Drupal\Core\Form\FormState::$internalStorage for documentation of the
+ * available flags.
+ *
+ * @see \Drupal\Core\Form\FormBuilderInterface
+ * @see \Drupal\Core\Form\FormValidatorInterface
+ * @see \Drupal\Core\Form\FormSubmitterInterface
  */
-interface FormErrorInterface {
+interface FormStateInterface {
+
+  /**
+   * Returns a reference to the complete form array.
+   *
+   * @return array
+   *   The complete form array.
+   */
+  public function &getCompleteForm();
+
+  /**
+   * Stores the complete form array.
+   *
+   * @param array $complete_form
+   *   The complete form array.
+   *
+   * @return $this
+   */
+  public function setCompleteForm(array &$complete_form);
+
+  /**
+   * Returns an array representation of the cacheable portion of the form state.
+   *
+   * @return array
+   *   The cacheable portion of the form state.
+   */
+  public function getCacheableArray();
+
+  /**
+   * Sets the value of the form state.
+   *
+   * @param array $form_state_additions
+   *   An array of values to add to the form state.
+   *
+   * @return $this
+   */
+  public function setFormState(array $form_state_additions);
+
+  /**
+   * Sets a value to an arbitrary property if it does not exist yet.
+   *
+   * @param string $property
+   *   The property to use for the value.
+   * @param mixed $value
+   *   The data to store.
+   *
+   * @return $this
+   */
+  public function setIfNotExists($property, $value);
+
+  /**
+   * Sets the redirect URL for the form.
+   *
+   * @param \Drupal\Core\Url $url
+   *   The URL to redirect to.
+   *
+   * @return $this
+   *
+   * @see \Drupal\Core\Form\FormSubmitterInterface::redirectForm()
+   */
+  public function setRedirect(Url $url);
+
+  /**
+   * Gets the value to use for redirecting after the form has been executed.
+   *
+   * @see \Drupal\Core\Form\FormSubmitterInterface::redirectForm()
+   *
+   * @return mixed
+   *   The value will be one of the following:
+   *   - A fully prepared \Symfony\Component\HttpFoundation\RedirectResponse.
+   *   - An instance of \Drupal\Core\Url to use for the redirect.
+   *   - A numerically-indexed array where the first value is the path to use
+   *     for the redirect, and the optional second value is an array of options
+   *     for generating the URL from the path.
+   *   - The path to use for the redirect.
+   *   - NULL, to signify that no redirect was specified and that the current
+   *     path should be used for the redirect.
+   *   - FALSE, to signify that no redirect should take place.
+   */
+  public function getRedirect();
+
+  /**
+   * Gets any arbitrary property.
+   *
+   * @param string $property
+   *   The property to retrieve.
+   *
+   * @return mixed
+   *   A reference to the value for that property, or NULL if the property does
+   *   not exist.
+   */
+  public function &get($property);
+
+  /**
+   * Sets a value to an arbitrary property.
+   *
+   * @param string $property
+   *   The property to use for the value.
+   * @param mixed $value
+   *   The value to set.
+   *
+   * @return $this
+   */
+  public function set($property, $value);
+
+  /**
+   * @param string $property
+   *   The property to use for the value.
+   */
+  public function has($property);
+
+  /**
+   * Adds a value to the build info.
+   *
+   * @param string $property
+   *   The property to use for the value.
+   * @param mixed $value
+   *   The value to set.
+   *
+   * @return $this
+   */
+  public function addBuildInfo($property, $value);
+
+  /**
+   * Returns the submitted and sanitized form values.
+   *
+   * @return array
+   *   An associative array of values submitted to the form.
+   */
+  public function getValues();
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addValue($property, $value);
+
+  /**
+   * Determines if any forms have any errors.
+   *
+   * @return bool
+   *   TRUE if any form has any errors, FALSE otherwise.
+   */
+  public static function hasAnyErrors();
 
   /**
    * Files an error against a form element.
@@ -99,35 +255,37 @@
    *   element is array('foo', 'bar', 'baz') then you may set an error on 'foo'
    *   or 'foo][bar][baz'. Setting an error on 'foo' sets an error for every
    *   element where the #parents array starts with 'foo'.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
    * @param string $message
    *   (optional) The error message to present to the user.
    *
-   * @return mixed
-   *   Return value is for internal use only. To get a list of errors, use
-   *   FormErrorInterface::getErrors() or FormErrorInterface::getError().
+   * @return $this
    */
-  public function setErrorByName($name, array &$form_state, $message = '');
+  public function setErrorByName($name, $message = '');
 
   /**
-   * Clears all errors against all form elements made by FormErrorInterface::setErrorByName().
+   * Flags an element as having an error.
+   *
+   * @param array $element
+   *   The form element.
+   * @param string $message
+   *   (optional) The error message to present to the user.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @return $this
    */
-  public function clearErrors(array &$form_state);
+  public function setError(&$element, $message = '');
+
+  /**
+   * Clears all errors against all form elements made by FormErrorInterface::setErrorByName().
+   */
+  public function clearErrors();
 
   /**
    * Returns an associative array of all errors.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
-   *
    * @return array
    *   An array of all errors, keyed by the name of the form element.
    */
-  public function getErrors(array $form_state);
+  public function getErrors();
 
   /**
    * Returns the error message filed against the given form element.
@@ -137,27 +295,20 @@ public function getErrors(array $form_state);
    *
    * @param array $element
    *   The form element to check for errors.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
    *
    * @return string|null
    *   Either the error message for this element or NULL if there are no errors.
    */
-  public function getError($element, array &$form_state);
+  public function getError($element);
 
   /**
-   * Flags an element as having an error.
-   */
-  public function setError(&$element, array &$form_state, $message = '');
-
-  /**
-   * Returns if there have been any errors during build.
+   * Sets the form to be rebuilt after processing.
    *
-   * This will include any forms built during this request.
+   * @param bool $rebuild
+   *   (optional) Whether the form should be rebuilt or not. Defaults to TRUE.
    *
-   * @return bool
-   *   Whether there have been any errors.
+   * @return $this
    */
-  public function getAnyErrors();
+  public function setRebuild($rebuild = TRUE);
 
 }
diff --git a/core/lib/Drupal/Core/Form/FormSubmitter.php b/core/lib/Drupal/Core/Form/FormSubmitter.php
index 78aca72..4c5d1c7 100644
--- a/core/lib/Drupal/Core/Form/FormSubmitter.php
+++ b/core/lib/Drupal/Core/Form/FormSubmitter.php
@@ -47,7 +47,7 @@ public function __construct(RequestStack $request_stack, UrlGeneratorInterface $
   /**
    * {@inheritdoc}
    */
-  public function doSubmitForm(&$form, &$form_state) {
+  public function doSubmitForm(&$form, FormStateInterface &$form_state) {
     if (!$form_state['submitted']) {
       return;
     }
@@ -61,18 +61,7 @@ public function doSubmitForm(&$form, &$form_state) {
     // \Drupal\Core\Form\FormBuilderInterface::submitForm).
     if ($batch = &$this->batchGet() && !isset($batch['current_set'])) {
       // Store $form_state information in the batch definition.
-      // We need the full $form_state when either:
-      // - Some submit handlers were saved to be called during batch
-      //   processing. See self::executeSubmitHandlers().
-      // - The form is multistep.
-      // In other cases, we only need the information expected by
-      // self::redirectForm().
-      if ($batch['has_form_submits'] || !empty($form_state['rebuild'])) {
-        $batch['form_state'] = $form_state;
-      }
-      else {
-        $batch['form_state'] = array_intersect_key($form_state, array_flip(array('programmed', 'rebuild', 'storage', 'no_redirect', 'redirect', 'redirect_route')));
-      }
+      $batch['form_state'] = $form_state;
 
       $batch['progressive'] = !$form_state['programmed'];
       $response = batch_process();
@@ -103,13 +92,13 @@ public function doSubmitForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function executeSubmitHandlers(&$form, &$form_state) {
+  public function executeSubmitHandlers(&$form, FormStateInterface &$form_state) {
     // If there was a button pressed, use its handlers.
-    if (isset($form_state['submit_handlers'])) {
+    if (!empty($form_state['submit_handlers'])) {
       $handlers = $form_state['submit_handlers'];
     }
     // Otherwise, check for a form-level handler.
-    elseif (isset($form['#submit'])) {
+    elseif (!empty($form['#submit'])) {
       $handlers = $form['#submit'];
     }
     else {
@@ -137,76 +126,53 @@ public function executeSubmitHandlers(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function redirectForm($form_state) {
-    // Skip redirection for form submissions invoked via
-    // \Drupal\Core\Form\FormBuilderInterface::submitForm().
-    if (!empty($form_state['programmed'])) {
-      return;
-    }
-    // Skip redirection if rebuild is activated.
-    if (!empty($form_state['rebuild'])) {
-      return;
-    }
-    // Skip redirection if it was explicitly disallowed.
-    if (!empty($form_state['no_redirect'])) {
-      return;
-    }
+  public function redirectForm(FormStateInterface $form_state) {
+    // According to RFC 7231, 303 See Other status code must be used to redirect
+    // user agent (and not default 302 Found).
+    // @see http://tools.ietf.org/html/rfc7231#section-6.4.4
+    $status_code = Response::HTTP_SEE_OTHER;
+    $redirect = $form_state->getRedirect();
 
     // Allow using redirect responses directly if needed.
-    if (isset($form_state['redirect']) && $form_state['redirect'] instanceof RedirectResponse) {
-      return $form_state['redirect'];
+    if ($redirect instanceof RedirectResponse) {
+      return $redirect;
     }
 
+    $url = NULL;
     // Check for a route-based redirection.
-    if (isset($form_state['redirect_route'])) {
-      // @todo Remove once all redirects are converted to Url.
-      if (!($form_state['redirect_route'] instanceof Url)) {
-        $form_state['redirect_route'] += array(
-          'route_parameters' => array(),
-          'options' => array(),
-        );
-        $form_state['redirect_route'] = new Url($form_state['redirect_route']['route_name'], $form_state['redirect_route']['route_parameters'], $form_state['redirect_route']['options']);
+    if ($redirect instanceof Url) {
+      $url = $redirect->toString();
+    }
+    // An array contains the path to use for the redirect, as well as options to
+    // use for generating the URL.
+    elseif (is_array($redirect)) {
+      if (isset($redirect[1])) {
+        $options = $redirect[1];
       }
-
-      $form_state['redirect_route']->setAbsolute();
-      // According to RFC 7231, 303 See Other status code must be used
-      // to redirect user agent (and not default 302 Found).
-      // @see http://tools.ietf.org/html/rfc7231#section-6.4.4
-      return new RedirectResponse($form_state['redirect_route']->toString(), Response::HTTP_SEE_OTHER);
+      else {
+        $options = array();
+      }
+      // Redirections should always use absolute URLs.
+      $options['absolute'] = TRUE;
+      if (isset($redirect[2])) {
+        $status_code = $redirect[2];
+      }
+      $url = $this->urlGenerator->generateFromPath($redirect[0], $options);
     }
-
-    // Only invoke a redirection if redirect value was not set to FALSE.
-    if (!isset($form_state['redirect']) || $form_state['redirect'] !== FALSE) {
-      if (isset($form_state['redirect'])) {
-        if (is_array($form_state['redirect'])) {
-          if (isset($form_state['redirect'][1])) {
-            $options = $form_state['redirect'][1];
-          }
-          else {
-            $options = array();
-          }
-          // Redirections should always use absolute URLs.
-          $options['absolute'] = TRUE;
-          if (isset($form_state['redirect'][2])) {
-            $status_code = $form_state['redirect'][2];
-          }
-          else {
-            $status_code = Response::HTTP_SEE_OTHER;
-          }
-          return new RedirectResponse($this->urlGenerator->generateFromPath($form_state['redirect'][0], $options), $status_code);
-        }
-        else {
-          // This function can be called from the installer, which guarantees
-          // that $redirect will always be a string, so catch that case here
-          // and use the appropriate redirect function.
-          if ($this->drupalInstallationAttempted()) {
-            install_goto($form_state['redirect']);
-          }
-          else {
-            return new RedirectResponse($this->urlGenerator->generateFromPath($form_state['redirect'], array('absolute' => TRUE)), Response::HTTP_SEE_OTHER);
-          }
-        }
+    // A string represents the path to use for the redirect.
+    elseif (is_string($redirect)) {
+      // This function can be called from the installer, which guarantees
+      // that $redirect will always be a string, so catch that case here
+      // and use the appropriate redirect function.
+      if ($this->drupalInstallationAttempted()) {
+        install_goto($redirect);
       }
+      else {
+        $url = $this->urlGenerator->generateFromPath($redirect, array('absolute' => TRUE));
+      }
+    }
+    // If no redirect was specified, redirect to the current path.
+    elseif ($redirect === NULL) {
       $request = $this->requestStack->getCurrentRequest();
       // @todo Remove dependency on the internal _system_path attribute:
       //   https://www.drupal.org/node/2293521.
@@ -214,7 +180,10 @@ public function redirectForm($form_state) {
         'query' => $request->query->all(),
         'absolute' => TRUE,
       ));
-      return new RedirectResponse($url, Response::HTTP_SEE_OTHER);
+    }
+
+    if ($url) {
+      return new RedirectResponse($url, $status_code);
     }
   }
 
diff --git a/core/lib/Drupal/Core/Form/FormSubmitterInterface.php b/core/lib/Drupal/Core/Form/FormSubmitterInterface.php
index 8ae8b08..8a79fe0 100644
--- a/core/lib/Drupal/Core/Form/FormSubmitterInterface.php
+++ b/core/lib/Drupal/Core/Form/FormSubmitterInterface.php
@@ -17,14 +17,14 @@
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return null|\Symfony\Component\HttpFoundation\Response
    *   If a response was set by a submit handler, or if the form needs to
    *   redirect, a Response object will be returned.
    */
-  public function doSubmitForm(&$form, &$form_state);
+  public function doSubmitForm(&$form, FormStateInterface &$form_state);
 
   /**
    * Executes custom submission handlers for a given form.
@@ -35,18 +35,18 @@ public function doSubmitForm(&$form, &$form_state);
    * @param $form
    *   An associative array containing the structure of the form.
    * @param $form_state
-   *   A keyed array containing the current state of the form. If the user
-   *   submitted the form by clicking a button with custom handler functions
-   *   defined, those handlers will be stored here.
+   *   The current state of the form. If the user submitted the form by clicking
+   *   a button with custom handler functions defined, those handlers will be
+   *   stored here.
    */
-  public function executeSubmitHandlers(&$form, &$form_state);
+  public function executeSubmitHandlers(&$form, FormStateInterface &$form_state);
 
   /**
    * Redirects the user to a URL after a form has been processed.
    *
    * After a form is submitted and processed, normally the user should be
    * redirected to a new destination page. This function figures out what that
-   * destination should be, based on the $form_state array and the 'destination'
+   * destination should be, based on the $form_state and the 'destination'
    * query string in the request URL, and redirects the user there.
    *
    * Usually (for exceptions, see below) $form_state['redirect'] determines
@@ -58,11 +58,11 @@ public function executeSubmitHandlers(&$form, &$form_state);
    *
    * Here is an example of how to set up a form to redirect to the path 'node':
    * @code
-   * $form_state['redirect'] = 'node';
+   * $form_state->set('redirect', 'node');
    * @endcode
    * And here is an example of how to redirect to 'node/123?foo=bar#baz':
    * @code
-   * $form_state['redirect'] = array(
+   * $form_state->set('redirect', array(
    *   'node/123',
    *   array(
    *     'query' => array(
@@ -70,7 +70,7 @@ public function executeSubmitHandlers(&$form, &$form_state);
    *     ),
    *     'fragment' => 'baz',
    *   ),
-   * );
+   * ));
    * @endcode
    *
    * There are several exceptions to the "usual" behavior described above:
@@ -94,13 +94,13 @@ public function executeSubmitHandlers(&$form, &$form_state);
    *   $form_state['redirect'].
    *
    * @param $form_state
-   *   An associative array containing the current state of the form.
+   *   The current state of the form.
    *
    * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
    *
    * @see \Drupal\Core\Form\FormBuilderInterface::processForm()
    * @see \Drupal\Core\Form\FormBuilderInterface::buildForm()
    */
-  public function redirectForm($form_state);
+  public function redirectForm(FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Form/FormValidator.php b/core/lib/Drupal/Core/Form/FormValidator.php
index eda8238..e35f06a 100644
--- a/core/lib/Drupal/Core/Form/FormValidator.php
+++ b/core/lib/Drupal/Core/Form/FormValidator.php
@@ -55,7 +55,7 @@ public function __construct(RequestStack $request_stack, TranslationInterface $s
   /**
    * {@inheritdoc}
    */
-  public function executeValidateHandlers(&$form, &$form_state) {
+  public function executeValidateHandlers(&$form, FormStateInterface &$form_state) {
     // If there was a button pressed, use its handlers.
     if (isset($form_state['validate_handlers'])) {
       $handlers = $form_state['validate_handlers'];
@@ -76,7 +76,7 @@ public function executeValidateHandlers(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm($form_id, &$form, &$form_state) {
+  public function validateForm($form_id, &$form, FormStateInterface &$form_state) {
     // If this form is flagged to always validate, ensure that previous runs of
     // validation are ignored.
     if (!empty($form_state['must_validate'])) {
@@ -119,12 +119,12 @@ public function validateForm($form_id, &$form, &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $form_id
    *   The unique string identifying the form.
    */
-  protected function handleErrorsWithLimitedValidation(&$form, &$form_state, $form_id) {
+  protected function handleErrorsWithLimitedValidation(&$form, FormStateInterface &$form_state, $form_id) {
     // If validation errors are limited then remove any non validated form values,
     // so that only values that passed validation are left for submit callbacks.
     if (isset($form_state['triggering_element']['#limit_validation_errors']) && $form_state['triggering_element']['#limit_validation_errors'] !== FALSE) {
@@ -171,12 +171,12 @@ protected function handleErrorsWithLimitedValidation(&$form, &$form_state, $form
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $form_id
    *   The unique string identifying the form.
    */
-  protected function finalizeValidation(&$form, &$form_state, $form_id) {
+  protected function finalizeValidation(&$form, FormStateInterface &$form_state, $form_id) {
     // After validation, loop through and assign each element its errors.
     $this->setElementErrorsFromFormState($form, $form_state);
     // Mark this form as validated.
@@ -192,12 +192,12 @@ protected function finalizeValidation(&$form, &$form_state, $form_id) {
    *
    * @param $elements
    *   An associative array containing the structure of the form.
-   * @param $form_state
-   *   A keyed array containing the current state of the form. The current
-   *   user-submitted data is stored in $form_state['values'], though
-   *   form validation functions are passed an explicit copy of the
-   *   values for the sake of simplicity. Validation handlers can also
-   *   $form_state to pass information on to submit handlers. For example:
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form. The current user-submitted data is stored
+   *   in $form_state['values'], though form validation functions are passed an
+   *   explicit copy of the values for the sake of simplicity. Validation
+   *   handlers can also $form_state to pass information on to submit handlers.
+   *   For example:
    *     $form_state['data_for_submission'] = $data;
    *   This technique is useful when validation requires file parsing,
    *   web service requests, or other expensive requests that should
@@ -206,7 +206,7 @@ protected function finalizeValidation(&$form, &$form_state, $form_id) {
    *   A unique string identifying the form for validation, submission,
    *   theming, and hook_form_alter functions.
    */
-  protected function doValidateForm(&$elements, &$form_state, $form_id = NULL) {
+  protected function doValidateForm(&$elements, FormStateInterface &$form_state, $form_id = NULL) {
     // Recurse through all children.
     foreach (Element::children($elements) as $key) {
       if (isset($elements[$key]) && $elements[$key]) {
@@ -289,18 +289,18 @@ protected function doValidateForm(&$elements, &$form_state, $form_id = NULL) {
    *
    * @param array $elements
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form. The current
-   *   user-submitted data is stored in $form_state['values'], though
-   *   form validation functions are passed an explicit copy of the
-   *   values for the sake of simplicity. Validation handlers can also
-   *   $form_state to pass information on to submit handlers. For example:
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form. The current user-submitted data is stored
+   *   in $form_state['values'], though form validation functions are passed an
+   *   explicit copy of the values for the sake of simplicity. Validation
+   *   handlers can also $form_state to pass information on to submit handlers.
+   *   For example:
    *     $form_state['data_for_submission'] = $data;
    *   This technique is useful when validation requires file parsing,
    *   web service requests, or other expensive requests that should
    *   not be repeated in the submission step.
    */
-  protected function performRequiredValidation(&$elements, &$form_state) {
+  protected function performRequiredValidation(&$elements, FormStateInterface &$form_state) {
     // Verify that the value is not longer than #maxlength.
     if (isset($elements['#maxlength']) && Unicode::strlen($elements['#value']) > $elements['#maxlength']) {
       $this->setError($elements, $form_state, $this->t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => Unicode::strlen($elements['#value']))));
@@ -345,12 +345,12 @@ protected function performRequiredValidation(&$elements, &$form_state) {
   /**
    * Determines if validation errors should be limited.
    *
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array|null
    */
-  protected function determineLimitValidationErrors(&$form_state) {
+  protected function determineLimitValidationErrors(FormStateInterface &$form_state) {
     // While this element is being validated, it may be desired that some
     // calls to self::setErrorByName() be suppressed and not result in a form
     // error, so that a button that implements low-risk functionality (such as
@@ -395,10 +395,10 @@ protected function determineLimitValidationErrors(&$form_state) {
    *
    * @param array $elements
    *   An associative array containing the structure of a form element.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  protected function setElementErrorsFromFormState(array &$elements, array &$form_state) {
+  protected function setElementErrorsFromFormState(array &$elements, FormStateInterface &$form_state) {
     // Recurse through all children.
     foreach (Element::children($elements) as $key) {
       if (isset($elements[$key]) && $elements[$key]) {
@@ -412,91 +412,43 @@ protected function setElementErrorsFromFormState(array &$elements, array &$form_
   /**
    * {@inheritdoc}
    */
-  public function setErrorByName($name, array &$form_state, $message = '') {
-    if (!empty($form_state['validation_complete'])) {
-      throw new \LogicException('Form errors cannot be set after form validation has finished.');
-    }
-
-    if (!isset($form_state['errors'][$name])) {
-      $record = TRUE;
-      if (isset($form_state['limit_validation_errors'])) {
-        // #limit_validation_errors is an array of "sections" within which user
-        // input must be valid. If the element is within one of these sections,
-        // the error must be recorded. Otherwise, it can be suppressed.
-        // #limit_validation_errors can be an empty array, in which case all
-        // errors are suppressed. For example, a "Previous" button might want
-        // its submit action to be triggered even if none of the submitted
-        // values are valid.
-        $record = FALSE;
-        foreach ($form_state['limit_validation_errors'] as $section) {
-          // Exploding by '][' reconstructs the element's #parents. If the
-          // reconstructed #parents begin with the same keys as the specified
-          // section, then the element's values are within the part of
-          // $form_state['values'] that the clicked button requires to be valid,
-          // so errors for this element must be recorded. As the exploded array
-          // will all be strings, we need to cast every value of the section
-          // array to string.
-          if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
-            $record = TRUE;
-            break;
-          }
-        }
-      }
-      if ($record) {
-        $form_state['errors'][$name] = $message;
-        $this->requestStack->getCurrentRequest()->attributes->set('_form_errors', TRUE);
-        if ($message) {
-          $this->drupalSetMessage($message, 'error');
-        }
-      }
-    }
-
-    return $form_state['errors'];
+  public function setErrorByName($name, FormStateInterface &$form_state, $message = '') {
+    return $form_state->setErrorByName($name, $message);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setError(&$element, array &$form_state, $message = '') {
-    $this->setErrorByName(implode('][', $element['#parents']), $form_state, $message);
+  public function setError(&$element, FormStateInterface &$form_state, $message = '') {
+    return $form_state->setError($element, $message);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getError($element, array &$form_state) {
-    if ($errors = $this->getErrors($form_state)) {
-      $parents = array();
-      foreach ($element['#parents'] as $parent) {
-        $parents[] = $parent;
-        $key = implode('][', $parents);
-        if (isset($errors[$key])) {
-          return $errors[$key];
-        }
-      }
-    }
+  public function getError($element, FormStateInterface &$form_state) {
+    return $form_state->getError($element);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function clearErrors(array &$form_state) {
-    $form_state['errors'] = array();
-    $this->requestStack->getCurrentRequest()->attributes->set('_form_errors', FALSE);
+  public function clearErrors(FormStateInterface &$form_state) {
+    $form_state->clearErrors();
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getErrors(array $form_state) {
-    return $form_state['errors'];
+  public function getErrors(FormStateInterface &$form_state) {
+    return $form_state->getErrors();
   }
 
   /**
    * {@inheritdoc}
    */
   public function getAnyErrors() {
-    return (bool) $this->requestStack->getCurrentRequest()->attributes->get('_form_errors');
+    return FormState::hasAnyErrors();
   }
 
   /**
@@ -506,13 +458,4 @@ protected function watchdog($type, $message, array $variables = array(), $severi
     watchdog($type, $message, $variables, $severity, $link);
   }
 
-  /**
-   * Wraps drupal_set_message().
-   *
-   * @return array|null
-   */
-  protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) {
-    return drupal_set_message($message, $type, $repeat);
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Form/FormValidatorInterface.php b/core/lib/Drupal/Core/Form/FormValidatorInterface.php
index 806e6a0..da8caa4 100644
--- a/core/lib/Drupal/Core/Form/FormValidatorInterface.php
+++ b/core/lib/Drupal/Core/Form/FormValidatorInterface.php
@@ -21,14 +21,14 @@
    * @param $form
    *   An associative array containing the structure of the form.
    * @param $form_state
-   *   A keyed array containing the current state of the form. If the user
-   *   submitted the form by clicking a button with custom handler functions
-   *   defined, those handlers will be stored here.
+   *   The current state of the form. If the user submitted the form by clicking
+   *   a button with custom handler functions defined, those handlers will be
+   *   stored here.
    */
-  public function executeValidateHandlers(&$form, &$form_state);
+  public function executeValidateHandlers(&$form, FormStateInterface &$form_state);
 
   /**
-   * Validates user-submitted form data in the $form_state array.
+   * Validates user-submitted form data in the $form_state.
    *
    * @param $form_id
    *   A unique string identifying the form for validation, submission,
@@ -42,16 +42,16 @@ public function executeValidateHandlers(&$form, &$form_state);
    *   elements in $form_state['values'] to prevent form submit handlers from
    *   receiving unvalidated values.
    * @param $form_state
-   *   A keyed array containing the current state of the form. The current
-   *   user-submitted data is stored in $form_state['values'], though
-   *   form validation functions are passed an explicit copy of the
-   *   values for the sake of simplicity. Validation handlers can also use
-   *   $form_state to pass information on to submit handlers. For example:
+   *   The current state of the form. The current user-submitted data is stored
+   *   in $form_state['values'], though form validation functions are passed an
+   *   explicit copy of the values for the sake of simplicity. Validation
+   *   handlers can also use $form_state to pass information on to submit
+   *   handlers. For example:
    *     $form_state['data_for_submission'] = $data;
    *   This technique is useful when validation requires file parsing,
    *   web service requests, or other expensive requests that should
    *   not be repeated in the submission step.
    */
-  public function validateForm($form_id, &$form, &$form_state);
+  public function validateForm($form_id, &$form, FormStateInterface &$form_state);
 
 }
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
index 30d424e..b50331a 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\ImageToolkit;
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Image\ImageInterface;
 
 /**
@@ -57,7 +58,7 @@ public function settingsForm();
    *
    * @see system_image_toolkit_settings_submit()
    */
-  public function settingsFormSubmit($form, &$form_state);
+  public function settingsFormSubmit($form, FormStateInterface $form_state);
 
   /**
    * Sets the image object that this toolkit instance is tied to.
diff --git a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
index d3667f7..a5c0737 100644
--- a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\UserAgent;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManager;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -28,7 +29,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $install_state = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $install_state = NULL) {
     if (count($install_state['translations']) > 1) {
       $files = $install_state['translations'];
     }
@@ -96,7 +97,7 @@ public function buildForm(array $form, array &$form_state, $install_state = NULL
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $install_state = &$form_state['build_info']['args'][0];
     $install_state['parameters']['langcode'] = $form_state['values']['langcode'];
   }
diff --git a/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php b/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php
index d88bc56..e16c10e 100644
--- a/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Installer\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides the profile selection form.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $install_state = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $install_state = NULL) {
     $form['#title'] = $this->t('Select an installation profile');
 
     $profiles = array();
@@ -87,7 +88,7 @@ public function buildForm(array $form, array &$form_state, $install_state = NULL
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     global $install_state;
     $install_state['parameters']['profile'] = $form_state['values']['profile'];
   }
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
index 745665b..491a1d9 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Locale\CountryManagerInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\user\UserStorageInterface;
@@ -88,7 +89,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Configure site');
 
     // Warn about settings.php permissions risk
@@ -227,7 +228,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if ($error = user_validate_name($form_state['values']['account']['name'])) {
       $this->setFormError('account][name', $form_state, $error);
     }
@@ -236,7 +237,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.site')
       ->set('name', $form_state['values']['site_name'])
       ->set('mail', $form_state['values']['site_mail'])
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
index 23f0d03..1020620 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a form to configure and rewrite settings.php.
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $conf_path = './' . conf_path(FALSE);
     $settings_file = $conf_path . '/settings.php';
 
@@ -114,7 +115,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $driver = $form_state['values']['driver'];
     $database = $form_state['values'][$driver];
     $drivers = drupal_get_database_types();
@@ -134,7 +135,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     global $install_state;
 
     // Update global settings array and save.
diff --git a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
index 234fcb5..af3d43c 100644
--- a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
+++ b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Menu\Form;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Menu\MenuLinkInterface;
 use Drupal\Core\Menu\MenuLinkManagerInterface;
 use Drupal\Core\Menu\MenuParentFormSelectorInterface;
@@ -101,7 +102,7 @@ public function setMenuLinkInstance(MenuLinkInterface $menu_link) {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Edit menu link %title', array('%title' => $this->menuLink->getTitle()));
 
     $provider = $this->menuLink->getProvider();
@@ -155,7 +156,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function extractFormValues(array &$form, array &$form_state) {
+  public function extractFormValues(array &$form, FormStateInterface $form_state) {
     $new_definition = array();
     $new_definition['hidden'] = $form_state['values']['enabled'] ? 0 : 1;
     $new_definition['weight'] = (int) $form_state['values']['weight'];
@@ -173,13 +174,13 @@ public function extractFormValues(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $new_definition = $this->extractFormValues($form, $form_state);
 
     return $this->menuLinkManager->updateDefinition($this->menuLink->getPluginId(), $new_definition);
diff --git a/core/lib/Drupal/Core/Menu/Form/MenuLinkFormInterface.php b/core/lib/Drupal/Core/Menu/Form/MenuLinkFormInterface.php
index f021890..fa0893b 100644
--- a/core/lib/Drupal/Core/Menu/Form/MenuLinkFormInterface.php
+++ b/core/lib/Drupal/Core/Menu/Form/MenuLinkFormInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Menu\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Menu\MenuLinkInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 
@@ -33,12 +34,12 @@ public function setMenuLinkInstance(MenuLinkInterface $menu_link);
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The new plugin definition values taken from the form values.
    */
-  public function extractFormValues(array &$form, array &$form_state);
+  public function extractFormValues(array &$form, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Menu/MenuLinkBase.php b/core/lib/Drupal/Core/Menu/MenuLinkBase.php
index 43cb49a..125bbf0 100644
--- a/core/lib/Drupal/Core/Menu/MenuLinkBase.php
+++ b/core/lib/Drupal/Core/Menu/MenuLinkBase.php
@@ -40,22 +40,6 @@ public function getWeight() {
   /**
    * {@inheritdoc}
    */
-  public function getTitle() {
-    // Subclasses may pull in the request or specific attributes as parameters.
-    $options = array();
-    if (!empty($this->pluginDefinition['title_context'])) {
-      $options['context'] = $this->pluginDefinition['title_context'];
-    }
-    $args = array();
-    if (isset($this->pluginDefinition['title_arguments']) && $title_arguments = $this->pluginDefinition['title_arguments']) {
-      $args = (array) $title_arguments;
-    }
-    return $this->t($this->pluginDefinition['title'], $args, $options);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getMenuName() {
     return $this->pluginDefinition['menu_name'];
   }
@@ -112,16 +96,6 @@ public function isDeletable() {
   /**
    * {@inheritdoc}
    */
-  public function getDescription() {
-    if ($this->pluginDefinition['description']) {
-      return $this->t($this->pluginDefinition['description']);
-    }
-    return '';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getOptions() {
     return $this->pluginDefinition['options'] ?: array();
   }
diff --git a/core/lib/Drupal/Core/Menu/MenuLinkDefault.php b/core/lib/Drupal/Core/Menu/MenuLinkDefault.php
index cf14df7..5d0f8e2 100644
--- a/core/lib/Drupal/Core/Menu/MenuLinkDefault.php
+++ b/core/lib/Drupal/Core/Menu/MenuLinkDefault.php
@@ -66,6 +66,32 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
+  public function getTitle() {
+    // Subclasses may pull in the request or specific attributes as parameters.
+    $options = array();
+    if (!empty($this->pluginDefinition['title_context'])) {
+      $options['context'] = $this->pluginDefinition['title_context'];
+    }
+    $args = array();
+    if (isset($this->pluginDefinition['title_arguments']) && $title_arguments = $this->pluginDefinition['title_arguments']) {
+      $args = (array) $title_arguments;
+    }
+    return $this->t($this->pluginDefinition['title'], $args, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    if ($this->pluginDefinition['description']) {
+      return $this->t($this->pluginDefinition['description']);
+    }
+    return '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function isResettable() {
     // The link can be reset if it has an override.
     return (bool) $this->staticOverride->loadOverride($this->getPluginId());
@@ -77,11 +103,13 @@ public function isResettable() {
   public function updateLink(array $new_definition_values, $persist) {
     // Filter the list of updates to only those that are allowed.
     $overrides = array_intersect_key($new_definition_values, $this->overrideAllowed);
+    // Update the definition.
+    $this->pluginDefinition = $overrides + $this->getPluginDefinition();
     if ($persist) {
+      // Always save the menu name as an override to avoid defaulting to tools.
+      $overrides['menu_name'] = $this->pluginDefinition['menu_name'];
       $this->staticOverride->saveOverride($this->getPluginId(), $overrides);
     }
-    // Update the definition.
-    $this->pluginDefinition = $overrides + $this->getPluginDefinition();
     return $this->pluginDefinition;
   }
 
diff --git a/core/lib/Drupal/Core/Menu/MenuLinkTree.php b/core/lib/Drupal/Core/Menu/MenuLinkTree.php
index 8d09c2c..e5d54fe 100644
--- a/core/lib/Drupal/Core/Menu/MenuLinkTree.php
+++ b/core/lib/Drupal/Core/Menu/MenuLinkTree.php
@@ -8,7 +8,9 @@
 namespace Drupal\Core\Menu;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Controller\ControllerResolverInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 
 /**
@@ -45,6 +47,30 @@ class MenuLinkTree implements MenuLinkTreeInterface {
   protected $controllerResolver;
 
   /**
+   * The cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cache;
+
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Stores the cached current route parameters by menu and current route match.
+   *
+   * @todo Remove this non-static caching in
+   *   https://www.drupal.org/node/1805054.
+   *
+   * @var \Drupal\Core\Menu\MenuTreeParameters[]
+   */
+  protected $cachedCurrentRouteParameters;
+
+  /**
    * Constructs a \Drupal\Core\Menu\MenuLinkTree object.
    *
    * @param \Drupal\Core\Menu\MenuTreeStorageInterface $tree_storage
@@ -57,31 +83,53 @@ class MenuLinkTree implements MenuLinkTreeInterface {
    *   The active menu trail service.
    * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
    *   The controller resolver.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   The cache backend.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    */
-  public function __construct(MenuTreeStorageInterface $tree_storage, MenuLinkManagerInterface $menu_link_manager, RouteProviderInterface $route_provider, MenuActiveTrailInterface $menu_active_trail, ControllerResolverInterface $controller_resolver) {
+  public function __construct(MenuTreeStorageInterface $tree_storage, MenuLinkManagerInterface $menu_link_manager, RouteProviderInterface $route_provider, MenuActiveTrailInterface $menu_active_trail, ControllerResolverInterface $controller_resolver, CacheBackendInterface $cache, RouteMatchInterface $route_match) {
     $this->treeStorage = $tree_storage;
     $this->menuLinkManager = $menu_link_manager;
     $this->routeProvider = $route_provider;
     $this->menuActiveTrail = $menu_active_trail;
     $this->controllerResolver = $controller_resolver;
+    // @todo Remove these two in https://www.drupal.org/node/1805054.
+    $this->cache = $cache;
+    $this->routeMatch = $route_match;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getCurrentRouteMenuTreeParameters($menu_name) {
-    $active_trail = $this->menuActiveTrail->getActiveTrailIds($menu_name);
-
-    $parameters = new MenuTreeParameters();
-    $parameters->setActiveTrail($active_trail)
-      // We want links in the active trail to be expanded.
-      ->addExpandedParents($active_trail)
-      // We marked the links in the active trail to be expanded, but we also
-      // want their descendants that have the "expanded" flag enabled to be
-      // expanded.
-      ->addExpandedParents($this->treeStorage->getExpanded($menu_name, $active_trail));
-
-    return $parameters;
+    $route_parameters = $this->routeMatch->getRawParameters()->all();
+    ksort($route_parameters);
+    $cid = 'current-route-parameters:' . $menu_name . ':route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters);
+
+    if (!isset($this->cachedCurrentRouteParameters[$menu_name])) {
+      $cache = $this->cache->get($cid);
+      if ($cache && $cache->data) {
+        $parameters = $cache->data;
+      }
+      else {
+        $active_trail = $this->menuActiveTrail->getActiveTrailIds($menu_name);
+
+        $parameters = new MenuTreeParameters();
+        $parameters->setActiveTrail($active_trail)
+          // We want links in the active trail to be expanded.
+          ->addExpandedParents($active_trail)
+          // We marked the links in the active trail to be expanded, but we also
+          // want their descendants that have the "expanded" flag enabled to be
+          // expanded.
+          ->addExpandedParents($this->treeStorage->getExpanded($menu_name, $active_trail));
+
+        $this->cache->set($cid, $parameters, CacheBackendInterface::CACHE_PERMANENT, array('menu' => $menu_name));
+      }
+      $this->cachedCurrentRouteParameters[$menu_name] = $parameters;
+    }
+
+    return $this->cachedCurrentRouteParameters[$menu_name];
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Plugin/PluginFormInterface.php b/core/lib/Drupal/Core/Plugin/PluginFormInterface.php
index daceeac..993c841 100644
--- a/core/lib/Drupal/Core/Plugin/PluginFormInterface.php
+++ b/core/lib/Drupal/Core/Plugin/PluginFormInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Plugin;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides an interface for a plugin that contains a form.
  *
@@ -19,32 +21,32 @@
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The form structure.
    */
-  public function buildConfigurationForm(array $form, array &$form_state);
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state);
 
   /**
    * Form validation handler.
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function validateConfigurationForm(array &$form, array &$form_state);
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state);
 
   /**
    * Form submission handler.
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function submitConfigurationForm(array &$form, array &$form_state);
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state);
 
 }
diff --git a/core/lib/Drupal/Core/Update/Form/UpdateScriptSelectionForm.php b/core/lib/Drupal/Core/Update/Form/UpdateScriptSelectionForm.php
index b6d440d..574ec6c 100644
--- a/core/lib/Drupal/Core/Update/Form/UpdateScriptSelectionForm.php
+++ b/core/lib/Drupal/Core/Update/Form/UpdateScriptSelectionForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Update\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides the list of available database module updates.
@@ -24,7 +25,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $count = 0;
     $incompatible_count = 0;
     $form['start'] = array(
@@ -127,7 +128,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php
index 4912a05..d3093ac 100644
--- a/core/lib/Drupal/Core/Utility/LinkGenerator.php
+++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php
@@ -99,7 +99,9 @@ public function generateFromUrl($text, Url $url) {
       // drupal.active-link library know the path in a standardized manner.
       if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
         // @todo System path is deprecated - use the route name and parameters.
-        $variables['options']['attributes']['data-drupal-link-system-path'] = $url->getInternalPath();
+        $system_path = $url->getInternalPath();
+        // Special case for the front page.
+        $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path;
       }
     }
 
diff --git a/core/modules/action/src/ActionAddForm.php b/core/modules/action/src/ActionAddForm.php
index bae8dcb..6d8e4aa 100644
--- a/core/modules/action/src/ActionAddForm.php
+++ b/core/modules/action/src/ActionAddForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Action\ActionManager;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -54,7 +55,7 @@ public static function create(ContainerInterface $container) {
    * @param string $action_id
    *   The hashed version of the action ID.
    */
-  public function buildForm(array $form, array &$form_state, $action_id = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $action_id = NULL) {
     // In \Drupal\action\Form\ActionAdminManageForm::buildForm() the action
     // are hashed. Here we have to decrypt it to find the desired action ID.
     foreach ($this->actionManager->getDefinitions() as $id => $definition) {
diff --git a/core/modules/action/src/ActionFormBase.php b/core/modules/action/src/ActionFormBase.php
index c2cbee3..23b7f07 100644
--- a/core/modules/action/src/ActionFormBase.php
+++ b/core/modules/action/src/ActionFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -53,7 +54,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $this->plugin = $this->entity->getPlugin();
     return parent::buildForm($form, $form_state);
   }
@@ -61,7 +62,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['label'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('Label'),
@@ -113,7 +114,7 @@ public function exists($id) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     unset($actions['delete']);
     return $actions;
@@ -122,7 +123,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     if ($this->plugin instanceof PluginFormInterface) {
@@ -133,7 +134,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     if ($this->plugin instanceof PluginFormInterface) {
@@ -145,7 +146,7 @@ public function submit(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $this->entity->save();
     drupal_set_message($this->t('The action has been successfully saved.'));
 
diff --git a/core/modules/action/src/Form/ActionAdminManageForm.php b/core/modules/action/src/Form/ActionAdminManageForm.php
index fd1a0d0..81c08f4 100644
--- a/core/modules/action/src/Form/ActionAdminManageForm.php
+++ b/core/modules/action/src/Form/ActionAdminManageForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Action\ActionManager;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -53,7 +54,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $actions = array();
     foreach ($this->manager->getDefinitions() as $id => $definition) {
       if (is_subclass_of($definition['class'], '\Drupal\Core\Plugin\PluginFormInterface')) {
@@ -87,7 +88,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['action']) {
       $form_state['redirect_route'] = array(
         'route_name' => 'action.admin_add',
diff --git a/core/modules/action/src/Form/ActionDeleteForm.php b/core/modules/action/src/Form/ActionDeleteForm.php
index 1ca080a..a65d574 100644
--- a/core/modules/action/src/Form/ActionDeleteForm.php
+++ b/core/modules/action/src/Form/ActionDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\action\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
 
     watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $this->entity->id(), '%action' => $this->entity->label()));
diff --git a/core/modules/action/src/Plugin/Action/EmailAction.php b/core/modules/action/src/Plugin/Action/EmailAction.php
index c6589a6..a9a00a9 100644
--- a/core/modules/action/src/Plugin/Action/EmailAction.php
+++ b/core/modules/action/src/Plugin/Action/EmailAction.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Action\ConfigurableActionBase;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Utility\Token;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -114,7 +115,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['recipient'] = array(
       '#type' => 'textfield',
       '#title' => t('Recipient'),
@@ -143,7 +144,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
     if (!valid_email_address($form_state['values']['recipient']) && strpos($form_state['values']['recipient'], ':mail') === FALSE) {
       // We want the literal %author placeholder to be emphasized in the error message.
       form_set_error('recipient', $form_state, t('Enter a valid email address or use a token email address such as %author.', array('%author' => '[node:author:mail]')));
@@ -153,7 +154,7 @@ public function validateConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['recipient'] = $form_state['values']['recipient'];
     $this->configuration['subject'] = $form_state['values']['subject'];
     $this->configuration['message'] = $form_state['values']['message'];
diff --git a/core/modules/action/src/Plugin/Action/GotoAction.php b/core/modules/action/src/Plugin/Action/GotoAction.php
index e08d91f..40ba621 100644
--- a/core/modules/action/src/Plugin/Action/GotoAction.php
+++ b/core/modules/action/src/Plugin/Action/GotoAction.php
@@ -8,6 +8,7 @@
 namespace Drupal\action\Plugin\Action;
 
 use Drupal\Core\Action\ConfigurableActionBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -94,7 +95,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['url'] = array(
       '#type' => 'textfield',
       '#title' => t('URL'),
@@ -108,7 +109,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['url'] = $form_state['values']['url'];
   }
 
diff --git a/core/modules/action/src/Plugin/Action/MessageAction.php b/core/modules/action/src/Plugin/Action/MessageAction.php
index cc15650..ece48fa 100644
--- a/core/modules/action/src/Plugin/Action/MessageAction.php
+++ b/core/modules/action/src/Plugin/Action/MessageAction.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Action\ConfigurableActionBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Utility\Token;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -68,7 +69,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['message'] = array(
       '#type' => 'textarea',
       '#title' => t('Message'),
@@ -83,7 +84,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['message'] = $form_state['values']['message'];
     unset($this->configuration['node']);
   }
diff --git a/core/modules/aggregator/src/FeedForm.php b/core/modules/aggregator/src/FeedForm.php
index e832d87..6d9d3ea 100644
--- a/core/modules/aggregator/src/FeedForm.php
+++ b/core/modules/aggregator/src/FeedForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -21,7 +22,7 @@ class FeedForm extends ContentEntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $feed = $this->entity;
 
     // @todo: convert to a language selection widget defined in the base field.
@@ -41,7 +42,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     $feed = $this->buildEntity($form, $form_state);
     // Check for duplicate titles.
     $feed_storage = $this->entityManager->getStorage('aggregator_feed');
@@ -60,7 +61,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $feed = $this->entity;
     $insert = (bool) $feed->id();
     $feed->save();
diff --git a/core/modules/aggregator/src/Form/FeedDeleteForm.php b/core/modules/aggregator/src/Form/FeedDeleteForm.php
index e7efd14..83c171e 100644
--- a/core/modules/aggregator/src/Form/FeedDeleteForm.php
+++ b/core/modules/aggregator/src/Form/FeedDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\aggregator\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     watchdog('aggregator', 'Feed %feed deleted.', array('%feed' => $this->entity->label()));
     drupal_set_message($this->t('The feed %feed has been deleted.', array('%feed' => $this->entity->label())));
diff --git a/core/modules/aggregator/src/Form/FeedItemsDeleteForm.php b/core/modules/aggregator/src/Form/FeedItemsDeleteForm.php
index 0da20f6..2d79aa2 100644
--- a/core/modules/aggregator/src/Form/FeedItemsDeleteForm.php
+++ b/core/modules/aggregator/src/Form/FeedItemsDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\aggregator\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->deleteItems();
 
     $form_state['redirect_route'] = $this->getCancelUrl();
diff --git a/core/modules/aggregator/src/Form/OpmlFeedAdd.php b/core/modules/aggregator/src/Form/OpmlFeedAdd.php
index 0613f48..3bed94f 100644
--- a/core/modules/aggregator/src/Form/OpmlFeedAdd.php
+++ b/core/modules/aggregator/src/Form/OpmlFeedAdd.php
@@ -10,6 +10,7 @@
 use Drupal\aggregator\FeedStorageInterface;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use GuzzleHttp\Exception\RequestException;
 use GuzzleHttp\ClientInterface;
@@ -66,7 +67,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $intervals = array(900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200);
     $period = array_map(array(\Drupal::service('date'), 'formatInterval'), array_combine($intervals, $intervals));
 
@@ -101,7 +102,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // If both fields are empty or filled, cancel.
     $file_upload = $this->getRequest()->files->get('files[upload]', NULL, TRUE);
     if (empty($form_state['values']['remote']) == empty($file_upload)) {
@@ -112,7 +113,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $validators = array('file_validate_extensions' => array('opml xml'));
     if ($file = file_save_upload('upload', $validators, FALSE, 0)) {
       $data = file_get_contents($file->getFileUri());
diff --git a/core/modules/aggregator/src/Form/SettingsForm.php b/core/modules/aggregator/src/Form/SettingsForm.php
index 075b614..3177742 100644
--- a/core/modules/aggregator/src/Form/SettingsForm.php
+++ b/core/modules/aggregator/src/Form/SettingsForm.php
@@ -10,6 +10,7 @@
 use Drupal\aggregator\Plugin\AggregatorPluginManager;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Form\ConfigFormBase;
@@ -98,7 +99,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('aggregator.settings');
 
     // Global aggregator settings.
@@ -187,7 +188,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     parent::validateForm($form, $form_state);
     // Let active plugins validate their settings.
     foreach ($this->configurableInstances as $instance) {
@@ -198,7 +199,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
     $config = $this->config('aggregator.settings');
     // Let active plugins save their settings.
diff --git a/core/modules/aggregator/src/Plugin/AggregatorPluginSettingsBase.php b/core/modules/aggregator/src/Plugin/AggregatorPluginSettingsBase.php
index ee94c7c..eb6ad36 100644
--- a/core/modules/aggregator/src/Plugin/AggregatorPluginSettingsBase.php
+++ b/core/modules/aggregator/src/Plugin/AggregatorPluginSettingsBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\aggregator\Plugin;
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Plugin\PluginFormInterface;
 
@@ -35,7 +36,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
diff --git a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
index 039ccea..38f4756 100644
--- a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
+++ b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
@@ -12,6 +12,7 @@
 use Drupal\aggregator\ItemStorageInterface;
 use Drupal\block\BlockBase;
 use Drupal\Core\Entity\Query\QueryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -114,9 +115,9 @@ protected function blockAccess(AccountInterface $account) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockForm().
+   * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     $feeds = $this->feedStorage->loadMultiple();
     $options = array();
     foreach ($feeds as $feed) {
@@ -139,9 +140,9 @@ public function blockForm($form, &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['block_count'] = $form_state['values']['block_count'];
     $this->configuration['feed'] = $form_state['values']['feed'];
   }
diff --git a/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php b/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
index 5fe77b8..c97c04d 100644
--- a/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
+++ b/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Datetime\Date as DateFormatter;
 use Drupal\Core\Entity\Query\QueryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -105,7 +106,7 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $processors = $this->configuration['processors'];
     $info = $this->getPluginDefinition();
     $counts = array(3, 5, 10, 15, 20, 25);
@@ -161,7 +162,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['items']['expire'] = $form_state['values']['aggregator_clear'];
     $this->configuration['items']['teaser_length'] = $form_state['values']['aggregator_teaser_length'];
     $this->configuration['source']['list_max'] = $form_state['values']['aggregator_summary_items'];
diff --git a/core/modules/aggregator/src/Plugin/views/field/TitleLink.php b/core/modules/aggregator/src/Plugin/views/field/TitleLink.php
index 725b82d..9ab50bf 100644
--- a/core/modules/aggregator/src/Plugin/views/field/TitleLink.php
+++ b/core/modules/aggregator/src/Plugin/views/field/TitleLink.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\aggregator\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
@@ -45,7 +46,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['display_as_link'] = array(
       '#title' => t('Display as link'),
       '#type' => 'checkbox',
diff --git a/core/modules/aggregator/src/Plugin/views/row/Rss.php b/core/modules/aggregator/src/Plugin/views/row/Rss.php
index f9a73a6..ff59828 100644
--- a/core/modules/aggregator/src/Plugin/views/row/Rss.php
+++ b/core/modules/aggregator/src/Plugin/views/row/Rss.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\aggregator\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\RowPluginBase;
 
 /**
@@ -51,7 +52,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['view_mode'] = array(
       '#type' => 'select',
       '#title' => t('Display type'),
diff --git a/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php b/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php
index 9b76fc9..b4f5fd5 100644
--- a/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php
+++ b/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php
@@ -11,6 +11,7 @@
 use Drupal\aggregator\Plugin\ProcessorInterface;
 use Drupal\aggregator\FeedInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -66,7 +67,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $processors = $this->configFactory->get('aggregator.settings')->get('processors');
     $info = $this->getPluginDefinition();
 
@@ -90,7 +91,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['items']['dummy_length'] = $form_state['values']['dummy_length'];
     $this->setConfiguration($this->configuration);
   }
diff --git a/core/modules/aggregator/tests/src/Plugin/AggregatorPluginSettingsBaseTest.php b/core/modules/aggregator/tests/src/Plugin/AggregatorPluginSettingsBaseTest.php
index b9390ff..90a4b69 100644
--- a/core/modules/aggregator/tests/src/Plugin/AggregatorPluginSettingsBaseTest.php
+++ b/core/modules/aggregator/tests/src/Plugin/AggregatorPluginSettingsBaseTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\aggregator\Tests\Plugin {
 
 use Drupal\aggregator\Form\SettingsForm;
+use Drupal\Core\Form\FormState;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -73,7 +74,7 @@ public function setUp() {
    */
   public function testSettingsForm() {
     // Emulate a form state of a sumbitted form.
-    $form_state = array('values' => array('dummy_length' => '', 'aggregator_allowed_html_tags' => ''));
+    $form_state = new FormState(array('values' => array('dummy_length' => '', 'aggregator_allowed_html_tags' => '')));
 
     $test_processor = $this->getMock(
       'Drupal\aggregator_test\Plugin\aggregator\processor\TestProcessor',
diff --git a/core/modules/ban/src/Form/BanAdmin.php b/core/modules/ban/src/Form/BanAdmin.php
index 3675e09..bd87ba8 100644
--- a/core/modules/ban/src/Form/BanAdmin.php
+++ b/core/modules/ban/src/Form/BanAdmin.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\ban\BanIpManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -54,7 +55,7 @@ public function getFormId() {
    *   \Drupal::formBuilder()->getForm() for use as the default value of the IP
    *   address form field.
    */
-  public function buildForm(array $form, array &$form_state, $default_ip = '') {
+  public function buildForm(array $form, FormStateInterface $form_state, $default_ip = '') {
     $rows = array();
     $header = array($this->t('banned IP addresses'), $this->t('Operations'));
     $result = $this->ipManager->findAll();
@@ -103,7 +104,7 @@ public function buildForm(array $form, array &$form_state, $default_ip = '') {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $ip = trim($form_state['values']['ip']);
     if ($this->ipManager->isBanned($ip)) {
       $this->setFormError('ip', $form_state, $this->t('This IP address is already banned.'));
@@ -119,7 +120,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $ip = trim($form_state['values']['ip']);
     $this->ipManager->banIp($ip);
     drupal_set_message($this->t('The IP address %ip has been banned.', array('%ip' => $ip)));
diff --git a/core/modules/ban/src/Form/BanDelete.php b/core/modules/ban/src/Form/BanDelete.php
index 1e41439..b607ba9 100644
--- a/core/modules/ban/src/Form/BanDelete.php
+++ b/core/modules/ban/src/Form/BanDelete.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\ban\BanIpManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -78,7 +79,7 @@ public function getCancelUrl() {
    * @param string $ban_id
    *   The IP address record ID to unban.
    */
-  public function buildForm(array $form, array &$form_state, $ban_id = '') {
+  public function buildForm(array $form, FormStateInterface $form_state, $ban_id = '') {
     if (!$this->banIp = $this->ipManager->findById($ban_id)) {
       throw new NotFoundHttpException();
     }
@@ -88,7 +89,7 @@ public function buildForm(array $form, array &$form_state, $ban_id = '') {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->ipManager->unbanIp($this->banIp);
     watchdog('user', 'Deleted %ip', array('%ip' => $this->banIp));
     drupal_set_message($this->t('The IP address %ip was deleted.', array('%ip' => $this->banIp)));
diff --git a/core/modules/block/src/BlockBase.php b/core/modules/block/src/BlockBase.php
index 70e83e8..ca94ba0 100644
--- a/core/modules/block/src/BlockBase.php
+++ b/core/modules/block/src/BlockBase.php
@@ -12,6 +12,8 @@
 use Drupal\Component\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Condition\ConditionAccessResolverTrait;
 use Drupal\Core\Condition\ConditionPluginBag;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContextAwarePluginBase;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\NestedArray;
@@ -198,7 +200,7 @@ protected function blockAccess(AccountInterface $account) {
    *
    * @see \Drupal\block\BlockBase::blockForm()
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $definition = $this->getPluginDefinition();
     $form['provider'] = array(
       '#type' => 'value',
@@ -323,7 +325,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     return array();
   }
 
@@ -335,7 +337,7 @@ public function blockForm($form, &$form_state) {
    *
    * @see \Drupal\block\BlockBase::blockValidate()
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
     // Remove the admin_label form item element value so it will not persist.
     unset($form_state['values']['admin_label']);
 
@@ -344,10 +346,12 @@ public function validateConfigurationForm(array &$form, array &$form_state) {
 
     foreach ($this->getVisibilityConditions() as $condition_id => $condition) {
       // Allow the condition to validate the form.
-      $condition_values = array(
-        'values' => &$form_state['values']['visibility'][$condition_id],
-      );
+      $condition_values = new FormState(array(
+        'values' => $form_state['values']['visibility'][$condition_id],
+      ));
       $condition->validateConfigurationForm($form, $condition_values);
+      // Update the original form values.
+      $form_state['values']['visibility'][$condition_id] = $condition_values['values'];
     }
 
     $this->blockValidate($form, $form_state);
@@ -356,7 +360,7 @@ public function validateConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockValidate($form, &$form_state) {}
+  public function blockValidate($form, FormStateInterface $form_state) {}
 
   /**
    * {@inheritdoc}
@@ -366,7 +370,7 @@ public function blockValidate($form, &$form_state) {}
    *
    * @see \Drupal\block\BlockBase::blockSubmit()
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     // Process the block's submission handling if no errors occurred only.
     if (!form_get_errors($form_state)) {
       $this->configuration['label'] = $form_state['values']['label'];
@@ -375,10 +379,12 @@ public function submitConfigurationForm(array &$form, array &$form_state) {
       $this->configuration['cache'] = $form_state['values']['cache'];
       foreach ($this->getVisibilityConditions() as $condition_id => $condition) {
         // Allow the condition to submit the form.
-        $condition_values = array(
-          'values' => &$form_state['values']['visibility'][$condition_id],
-        );
+        $condition_values = new FormState(array(
+          'values' => $form_state['values']['visibility'][$condition_id],
+        ));
         $condition->submitConfigurationForm($form, $condition_values);
+        // Update the original form values.
+        $form_state['values']['visibility'][$condition_id] = $condition_values['values'];
       }
       $this->blockSubmit($form, $form_state);
     }
@@ -387,7 +393,7 @@ public function submitConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {}
+  public function blockSubmit($form, FormStateInterface $form_state) {}
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/block/src/BlockForm.php b/core/modules/block/src/BlockForm.php
index f562f52..704f3d1 100644
--- a/core/modules/block/src/BlockForm.php
+++ b/core/modules/block/src/BlockForm.php
@@ -9,6 +9,8 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -52,7 +54,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
 
     // Store theme settings in $form_state for use below.
@@ -125,7 +127,7 @@ public function form(array $form, array &$form_state) {
   /**
    * Handles switching the available regions based on the selected theme.
    */
-  public function themeSwitch($form, &$form_state) {
+  public function themeSwitch($form, FormStateInterface $form_state) {
     $form['region']['#options'] = system_region_list($form_state['values']['theme'], REGIONS_VISIBLE);
     return $form['region'];
   }
@@ -133,7 +135,7 @@ public function themeSwitch($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Save block');
     return $actions;
@@ -142,35 +144,38 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     // The Block Entity form puts all block plugin form elements in the
     // settings form element, so just pass that to the block for validation.
-    $settings = array(
-      'values' => &$form_state['values']['settings']
-    );
+    $settings = new FormState(array(
+      'values' => $form_state['values']['settings']
+    ));
     // Call the plugin validate handler.
     $this->entity->getPlugin()->validateConfigurationForm($form, $settings);
+    // Update the original form values.
+    $form_state['values']['settings'] = $settings['values'];
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     $entity = $this->entity;
     // The Block Entity form puts all block plugin form elements in the
     // settings form element, so just pass that to the block for submission.
     // @todo Find a way to avoid this manipulation.
-    $settings = array(
-      'values' => &$form_state['values']['settings'],
-      'errors' => $form_state['errors'],
-    );
+    $settings = new FormState(array(
+      'values' => $form_state['values']['settings'],
+    ));
 
     // Call the plugin submit handler.
     $entity->getPlugin()->submitConfigurationForm($form, $settings);
+    // Update the original form values.
+    $form_state['values']['settings'] = $settings['values'];
 
     // Save the settings of the plugin.
     $entity->save();
diff --git a/core/modules/block/src/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php
index 1bf034d..1b26b9f 100644
--- a/core/modules/block/src/BlockListBuilder.php
+++ b/core/modules/block/src/BlockListBuilder.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -133,7 +134,7 @@ public function getFormId() {
    *
    * Form constructor for the main block administration form.
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $placement = FALSE;
     if ($this->request->query->has('block-placement')) {
       $placement = $this->request->query->get('block-placement');
@@ -388,7 +389,7 @@ public function getDefaultOperations(EntityInterface $entity) {
   /**
    * Implements \Drupal\Core\Form\FormInterface::validateForm().
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // No validation.
   }
 
@@ -397,7 +398,7 @@ public function validateForm(array &$form, array &$form_state) {
    *
    * Form submission handler for the main block administration form.
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $entities = entity_load_multiple('block', array_keys($form_state['values']['blocks']));
     foreach ($entities as $entity_id => $entity) {
       $entity->set('weight', $form_state['values']['blocks'][$entity_id]['weight']);
diff --git a/core/modules/block/src/BlockPluginInterface.php b/core/modules/block/src/BlockPluginInterface.php
index f1a94ca..05d0ce5 100644
--- a/core/modules/block/src/BlockPluginInterface.php
+++ b/core/modules/block/src/BlockPluginInterface.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Cache\CacheableInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\Session\AccountInterface;
 
@@ -88,47 +89,47 @@ public function setConfigurationValue($key, $value);
    *
    * @param array $form
    *   The form definition array for the block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array $form
    *   The renderable form array representing the entire configuration form.
    */
-  public function blockForm($form, &$form_state);
+  public function blockForm($form, FormStateInterface $form_state);
 
   /**
    * Adds block type-specific validation for the block form.
    *
-   * Note that this method takes the form structure and form state arrays for
-   * the full block configuration form as arguments, not just the elements
-   * defined in BlockPluginInterface::blockForm().
+   * Note that this method takes the form structure and form state for the full
+   * block configuration form as arguments, not just the elements defined in
+   * BlockPluginInterface::blockForm().
    *
    * @param array $form
    *   The form definition array for the full block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @see \Drupal\block\BlockPluginInterface::blockForm()
    * @see \Drupal\block\BlockPluginInterface::blockSubmit()
    */
-  public function blockValidate($form, &$form_state);
+  public function blockValidate($form, FormStateInterface $form_state);
 
   /**
    * Adds block type-specific submission handling for the block form.
    *
-   * Note that this method takes the form structure and form state arrays for
-   * the full block configuration form as arguments, not just the elements
-   * defined in BlockPluginInterface::blockForm().
+   * Note that this method takes the form structure and form state for the full
+   * block configuration form as arguments, not just the elements defined in
+   * BlockPluginInterface::blockForm().
    *
    * @param array $form
    *   The form definition array for the full block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @see \Drupal\block\BlockPluginInterface::blockForm()
    * @see \Drupal\block\BlockPluginInterface::blockValidate()
    */
-  public function blockSubmit($form, &$form_state);
+  public function blockSubmit($form, FormStateInterface $form_state);
 
   /**
    * Suggests a machine name to identify an instance of this block.
diff --git a/core/modules/block/src/Form/BlockDeleteForm.php b/core/modules/block/src/Form/BlockDeleteForm.php
index 336888f..d811247 100644
--- a/core/modules/block/src/Form/BlockDeleteForm.php
+++ b/core/modules/block/src/Form/BlockDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\block\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message($this->t('The block %name has been removed.', array('%name' => $this->entity->label())));
     $form_state['redirect_route'] = $this->getCancelUrl();
diff --git a/core/modules/block/src/Plugin/views/display/Block.php b/core/modules/block/src/Plugin/views/display/Block.php
index 9ee2ca9..0e2e968 100644
--- a/core/modules/block/src/Plugin/views/display/Block.php
+++ b/core/modules/block/src/Plugin/views/display/Block.php
@@ -9,6 +9,7 @@
 namespace Drupal\block\Plugin\views\display;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\Block\ViewsBlock;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Views;
@@ -140,7 +141,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     switch ($form_state['section']) {
@@ -201,7 +202,7 @@ public function buildOptionsForm(&$form, &$form_state) {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
     switch ($form_state['section']) {
       case 'block_description':
@@ -222,15 +223,15 @@ public function submitOptionsForm(&$form, &$form_state) {
    *   The ViewsBlock plugin.
    * @param array $form
    *   The form definition array for the block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array $form
    *   The renderable form array representing the entire configuration form.
    *
    * @see \Drupal\views\Plugin\Block\ViewsBlock::blockForm()
    */
-  public function blockForm(ViewsBlock $block, array &$form, array &$form_state) {
+  public function blockForm(ViewsBlock $block, array &$form, FormStateInterface $form_state) {
     $allow_settings = array_filter($this->getOption('allow'));
 
     $block_configuration = $block->getConfiguration();
@@ -267,12 +268,12 @@ public function blockForm(ViewsBlock $block, array &$form, array &$form_state) {
    *   The ViewsBlock plugin.
    * @param array $form
    *   The form definition array for the block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @see \Drupal\views\Plugin\Block\ViewsBlock::blockValidate()
    */
-  public function blockValidate(ViewsBlock $block, array $form, array &$form_state) {
+  public function blockValidate(ViewsBlock $block, array $form, FormStateInterface $form_state) {
   }
 
   /**
@@ -282,12 +283,12 @@ public function blockValidate(ViewsBlock $block, array $form, array &$form_state
    *   The ViewsBlock plugin.
    * @param array $form
    *   The form definition array for the full block configuration form.
-   * @param array $form_state
-   *   An array containing the current state of the configuration form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * * @see \Drupal\views\Plugin\Block\ViewsBlock::blockSubmit()
    */
-  public function blockSubmit(ViewsBlock $block, $form, &$form_state) {
+  public function blockSubmit(ViewsBlock $block, $form, FormStateInterface $form_state) {
     if (isset($form_state['values']['override']['items_per_page'])) {
       $block->setConfigurationValue('items_per_page', $form_state['values']['override']['items_per_page']);
     }
diff --git a/core/modules/block/src/Tests/BlockInterfaceTest.php b/core/modules/block/src/Tests/BlockInterfaceTest.php
index bd4c55c..29097e5 100644
--- a/core/modules/block/src/Tests/BlockInterfaceTest.php
+++ b/core/modules/block/src/Tests/BlockInterfaceTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\block\Tests;
 
+use Drupal\Core\Form\FormState;
 use Drupal\simpletest\DrupalUnitTestBase;
 use Drupal\block\BlockInterface;
 
@@ -118,7 +119,7 @@ public function testBlockInterface() {
         '#default_value' => 'My custom display message.',
       ),
     );
-    $form_state = array();
+    $form_state = new FormState();
     // Ensure there are no form elements that do not belong to the plugin.
     $actual_form = $display_block->buildConfigurationForm(array(), $form_state);
     // Remove the visibility sections, as that just tests condition plugins.
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php
index 9a4db70..255ba63 100644
--- a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php
@@ -8,6 +8,7 @@
 namespace Drupal\block_test\Plugin\Block;
 
 use Drupal\block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -39,7 +40,7 @@ protected function blockAccess(AccountInterface $account) {
   /**
    * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     $form['display_message'] = array(
       '#type' => 'textfield',
       '#title' => t('Display message'),
@@ -51,7 +52,7 @@ public function blockForm($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['display_message'] = $form_state['values']['display_message'];
   }
 
diff --git a/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block.yml b/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block.yml
index ce61f44..e16db6b 100644
--- a/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block.yml
+++ b/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block.yml
@@ -38,6 +38,7 @@ display:
     id: block_1
     display_title: Block
     position: null
+    provider: block
     display_options:
       field:
         title:
@@ -46,3 +47,6 @@ label: test_view_block
 module: views
 id: test_view_block
 tag: ''
+dependencies:
+  module:
+    - block
diff --git a/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block2.yml b/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block2.yml
index 938220e..45750f4 100644
--- a/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block2.yml
+++ b/core/modules/block/tests/modules/block_test_views/test_views/views.view.test_view_block2.yml
@@ -34,6 +34,7 @@ display:
           provider: views_test_data
       title: test_view_block2
   block_1:
+    provider: block
     display_plugin: block
     id: block_1
     display_title: Block
@@ -43,6 +44,7 @@ display:
         title:
           link_to_node: true
   block_2:
+    provider: block
     display_plugin: block
     id: block_2
     display_title: Block
@@ -52,6 +54,7 @@ display:
         title:
           link_to_node: true
   block_3:
+    provider: block
     display_plugin: block
     id: block_3
     display_title: Block
@@ -65,3 +68,6 @@ label: test_view_block2
 module: views
 id: test_view_block2
 tag: ''
+dependencies:
+  module:
+    - block
diff --git a/core/modules/block_content/src/BlockContentForm.php b/core/modules/block_content/src/BlockContentForm.php
index 22ef45b..1524f42 100644
--- a/core/modules/block_content/src/BlockContentForm.php
+++ b/core/modules/block_content/src/BlockContentForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -83,7 +84,7 @@ protected function prepareEntity() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $block = $this->entity;
     $account = $this->currentUser();
 
@@ -174,7 +175,7 @@ public function form(array $form, array &$form_state) {
    * form state's entity with the current step's values before proceeding to the
    * next step.
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // Build the block object from the submitted values.
     $block = parent::submit($form, $form_state);
 
@@ -189,7 +190,7 @@ public function submit(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $block = $this->entity;
     $insert = $block->isNew();
     $block->save();
@@ -236,7 +237,7 @@ public function save(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if ($this->entity->isNew()) {
       $exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state['values']['info']));
       if (!empty($exists)) {
diff --git a/core/modules/block_content/src/BlockContentTranslationHandler.php b/core/modules/block_content/src/BlockContentTranslationHandler.php
index 148e249..ca7a6d9 100644
--- a/core/modules/block_content/src/BlockContentTranslationHandler.php
+++ b/core/modules/block_content/src/BlockContentTranslationHandler.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines the translation handler for custom blocks.
@@ -18,7 +19,7 @@ class BlockContentTranslationHandler extends ContentTranslationHandler {
   /**
    * {@inheritdoc}
    */
-  public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity) {
+  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
     parent::entityFormAlter($form, $form_state, $entity);
     // Move the translation fieldset to a vertical tab.
     if (isset($form['translation'])) {
diff --git a/core/modules/block_content/src/BlockContentTypeForm.php b/core/modules/block_content/src/BlockContentTypeForm.php
index e64bfa3..025d673 100644
--- a/core/modules/block_content/src/BlockContentTypeForm.php
+++ b/core/modules/block_content/src/BlockContentTypeForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Base form for category edit forms.
@@ -16,9 +17,9 @@
 class BlockContentTypeForm extends EntityForm {
 
   /**
-   * Overrides \Drupal\Core\Entity\EntityForm::form().
+   * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $block_type = $this->entity;
@@ -87,7 +88,7 @@ public function form(array $form, array &$form_state) {
   /**
    * Overrides \Drupal\Core\Entity\EntityForm::save().
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $block_type = $this->entity;
     $status = $block_type->save();
 
diff --git a/core/modules/block_content/src/Form/BlockContentDeleteForm.php b/core/modules/block_content/src/Form/BlockContentDeleteForm.php
index 6367c87..88249ae 100644
--- a/core/modules/block_content/src/Form/BlockContentDeleteForm.php
+++ b/core/modules/block_content/src/Form/BlockContentDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\block_content\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $instances = $this->entity->getInstances();
 
     $form['message'] = array(
@@ -53,7 +54,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message($this->t('Custom block %label has been deleted.', array('%label' => $this->entity->label())));
     watchdog('block_content', 'Custom block %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php b/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php
index c4ef05a..decda49 100644
--- a/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php
+++ b/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -67,7 +68,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $blocks = $this->queryFactory->get('block_content')->condition('type', $this->entity->id())->execute();
     if (!empty($blocks)) {
       $caption = '<p>' . format_plural(count($blocks), '%label is used by 1 custom block on your site. You can not remove this block type until you have removed all of the %label blocks.', '%label is used by @count custom blocks on your site. You may not remove %label until you have removed all of the %label custom blocks.', array('%label' => $this->entity->label())) . '</p>';
@@ -82,7 +83,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message(t('Custom block type %label has been deleted.', array('%label' => $this->entity->label())));
     watchdog('block_content', 'Custom block type %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php
index 49a53dc..8a5a409 100644
--- a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php
+++ b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php
@@ -11,6 +11,7 @@
 use Drupal\block\BlockManagerInterface;
 use Drupal\Core\Entity\EntityManager;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -120,7 +121,7 @@ public function defaultConfiguration() {
    *
    * Adds body and description fields to the block configuration form.
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     $form['block_content']['view_mode'] = array(
       '#type' => 'select',
       '#options' => $this->entityManager->getViewModeOptions('block_content'),
@@ -133,9 +134,9 @@ public function blockForm($form, &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     // Invalidate the block cache to update custom block-based derivatives.
     if ($this->moduleHandler->moduleExists('block')) {
       $this->configuration['view_mode'] = $form_state['values']['block_content']['view_mode'];
diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc
index 9a55869..6a3edc1 100644
--- a/core/modules/book/book.admin.inc
+++ b/core/modules/book/book.admin.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\book\BookManager;
 use Drupal\Core\Render\Element;
 
 /**
@@ -87,7 +88,7 @@ function theme_book_admin_table($variables) {
         'subgroup' => 'book-pid',
         'source' => 'book-nid',
         'hidden' => TRUE,
-        'limit' => MENU_MAX_DEPTH - 2,
+        'limit' => BookManager::BOOK_MAX_DEPTH - 2,
       ),
       array(
         'action' => 'order',
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index ba00049..c791b68 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -5,9 +5,11 @@
  * Allows users to create and organize related content in an outline.
  */
 
+use Drupal\book\BookManager;
 use Drupal\book\BookManagerInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\node\NodeInterface;
@@ -123,7 +125,7 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
       if ($context['view_mode'] == 'full' && node_is_page($node)) {
         $child_type = \Drupal::config('book.settings')->get('child_type');
         $access_controller = \Drupal::entityManager()->getAccessController('node');
-        if (($account->hasPermission('add content to books') || $account->hasPermission('administer book outlines')) && $access_controller->createAccess($child_type) && $node->isPublished() && $node->book['depth'] < MENU_MAX_DEPTH) {
+        if (($account->hasPermission('add content to books') || $account->hasPermission('administer book outlines')) && $access_controller->createAccess($child_type) && $node->isPublished() && $node->book['depth'] < BookManager::BOOK_MAX_DEPTH) {
           $links['book_add_child'] = array(
             'title' => t('Add child page'),
             'href' => 'node/add/' . $child_type,
@@ -158,7 +160,7 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
  *
  * @see book_pick_book_nojs_submit()
  */
-function book_form_node_form_alter(&$form, &$form_state, $form_id) {
+function book_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $node = $form_state['controller']->getEntity();
   $account = \Drupal::currentUser();
   $access = $account->hasPermission('administer book outlines');
@@ -193,7 +195,7 @@ function book_form_node_form_alter(&$form, &$form_state, $form_id) {
  *
  * @todo: Remove this in favor of an entity field.
  */
-function book_node_builder($entity_type, NodeInterface $entity, &$form, &$form_state) {
+function book_node_builder($entity_type, NodeInterface $entity, &$form, FormStateInterface $form_state) {
   $entity->book = $form_state['values']['book'];
 
   // Always save a revision for non-administrators.
@@ -214,7 +216,7 @@ function book_node_builder($entity_type, NodeInterface $entity, &$form, &$form_s
  * @see book_form_update()
  * @see book_form_node_form_alter()
  */
-function book_pick_book_nojs_submit($form, &$form_state) {
+function book_pick_book_nojs_submit($form, FormStateInterface $form_state) {
   $node = $form_state['controller']->getEntity();
   $node->book = $form_state['values']['book'];
   $form_state['rebuild'] = TRUE;
@@ -309,7 +311,7 @@ function book_node_predelete(EntityInterface $node) {
 /**
  * Implements hook_node_prepare_form().
  */
-function book_node_prepare_form(NodeInterface $node, $operation, array &$form_state) {
+function book_node_prepare_form(NodeInterface $node, $operation, FormStateInterface $form_state) {
   /** @var \Drupal\book\BookManagerInterface $book_manager */
   $book_manager = \Drupal::service('book.manager');
 
diff --git a/core/modules/book/src/BookManager.php b/core/modules/book/src/BookManager.php
index c491cf4..45f9adf 100644
--- a/core/modules/book/src/BookManager.php
+++ b/core/modules/book/src/BookManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
@@ -168,7 +169,7 @@ protected function findChildrenRelativeDepth(array $book_link) {
   /**
    * {@inheritdoc}
    */
-  public function addFormElements(array $form, array &$form_state, NodeInterface $node, AccountInterface $account, $collapsed = TRUE) {
+  public function addFormElements(array $form, FormStateInterface $form_state, NodeInterface $node, AccountInterface $account, $collapsed = TRUE) {
     // If the form is being processed during the Ajax callback of our book bid
     // dropdown, then $form_state will hold the value that was selected.
     if (isset($form_state['values']['book'])) {
diff --git a/core/modules/book/src/BookManagerInterface.php b/core/modules/book/src/BookManagerInterface.php
index 81dfe08..72ca61e 100644
--- a/core/modules/book/src/BookManagerInterface.php
+++ b/core/modules/book/src/BookManagerInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\book;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\node\NodeInterface;
 
@@ -203,8 +204,8 @@ public function getBookParents(array $item, array $parent = array());
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\node\NodeInterface $node
    *   The node whose form is being viewed.
    * @param \Drupal\Core\Session\AccountInterface $account
@@ -215,7 +216,7 @@ public function getBookParents(array $item, array $parent = array());
    * @return array
    *   The form structure, with the book elements added.
    */
-  public function addFormElements(array $form, array &$form_state, NodeInterface $node, AccountInterface $account, $collapsed = TRUE);
+  public function addFormElements(array $form, FormStateInterface $form_state, NodeInterface $node, AccountInterface $account, $collapsed = TRUE);
 
   /**
    * Deletes node's entry from book table.
diff --git a/core/modules/book/src/Form/BookAdminEditForm.php b/core/modules/book/src/Form/BookAdminEditForm.php
index f52c2e4..9a342f0 100644
--- a/core/modules/book/src/Form/BookAdminEditForm.php
+++ b/core/modules/book/src/Form/BookAdminEditForm.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -68,7 +69,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, NodeInterface $node = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, NodeInterface $node = NULL) {
     $form['#title'] = $node->label();
     $form['#node'] = $node;
     $this->bookAdminTable($node, $form);
@@ -83,7 +84,7 @@ public function buildForm(array $form, array &$form_state, NodeInterface $node =
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['tree_hash'] != $form_state['values']['tree_current_hash']) {
       $this->setFormError('', $form_state, $this->t('This book has been modified by another user, the changes could not be saved.'));
     }
@@ -92,7 +93,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Save elements in the same order as defined in post rather than the form.
     // This ensures parents are updated before their children, preventing orphans.
     $order = array_flip(array_keys($form_state['input']['table']));
diff --git a/core/modules/book/src/Form/BookOutlineForm.php b/core/modules/book/src/Form/BookOutlineForm.php
index f4a97a1..82a07aa 100644
--- a/core/modules/book/src/Form/BookOutlineForm.php
+++ b/core/modules/book/src/Form/BookOutlineForm.php
@@ -10,6 +10,7 @@
 use Drupal\book\BookManagerInterface;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -64,7 +65,7 @@ public function getBaseFormID() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->entity->label();
 
     if (!isset($this->entity->book)) {
@@ -87,7 +88,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->entity->book['original_bid'] ? $this->t('Update book outline') : $this->t('Add to book outline');
     $actions['delete']['#value'] = $this->t('Remove from book outline');
@@ -100,7 +101,7 @@ protected function actions(array $form, array &$form_state) {
    *
    * @see book_remove_button_submit()
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = array(
       'route_name' => 'node.view',
       'route_parameters' => array(
@@ -132,7 +133,7 @@ public function submit(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function delete(array $form, array &$form_state) {
+  public function delete(array $form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = $this->entity->urlInfo('book-remove-form');
   }
 
diff --git a/core/modules/book/src/Form/BookRemoveForm.php b/core/modules/book/src/Form/BookRemoveForm.php
index b24bc51..8ea7342 100644
--- a/core/modules/book/src/Form/BookRemoveForm.php
+++ b/core/modules/book/src/Form/BookRemoveForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\book\BookManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -61,7 +62,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, NodeInterface $node = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, NodeInterface $node = NULL) {
     $this->node = $node;
     return parent::buildForm($form, $form_state);
   }
@@ -103,7 +104,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($this->bookManager->checkNodeIsRemovable($this->node)) {
       $this->bookManager->deleteFromBook($this->node->id());
       drupal_set_message($this->t('The post has been removed from the book.'));
diff --git a/core/modules/book/src/Form/BookSettingsForm.php b/core/modules/book/src/Form/BookSettingsForm.php
index 140f8e5..4a7535e 100644
--- a/core/modules/book/src/Form/BookSettingsForm.php
+++ b/core/modules/book/src/Form/BookSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\book\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure book settings for this site.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $types = node_type_get_names();
     $config = $this->config('book.settings');
     $form['book_allowed_types'] = array(
@@ -50,7 +51,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $child_type = $form_state['values']['book_child_type'];
     if (empty($form_state['values']['book_allowed_types'][$child_type])) {
       $this->setFormError('book_child_type', $form_state, $this->t('The content type for the %add-child link must be one of those selected as an allowed book outline type.', array('%add-child' => $this->t('Add child page'))));
@@ -62,7 +63,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $allowed_types = array_filter($form_state['values']['book_allowed_types']);
     // We need to save the allowed types in an array ordered by machine_name so
     // that we can save them in the correct order if node type changes.
diff --git a/core/modules/book/src/Plugin/Block/BookNavigationBlock.php b/core/modules/book/src/Plugin/Block/BookNavigationBlock.php
index 5e85d99..51d0a0d 100644
--- a/core/modules/book/src/Plugin/Block/BookNavigationBlock.php
+++ b/core/modules/book/src/Plugin/Block/BookNavigationBlock.php
@@ -9,6 +9,7 @@
 
 use Drupal\block\BlockBase;
 use Drupal\book\BookManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -82,9 +83,9 @@ public function defaultConfiguration() {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockForm()
+   * {@inheritdoc}
    */
-  function blockForm($form, &$form_state) {
+  function blockForm($form, FormStateInterface $form_state) {
     $options = array(
       'all pages' => t('Show block on all pages'),
       'book pages' => t('Show block only on book pages'),
@@ -101,9 +102,9 @@ function blockForm($form, &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['block_mode'] = $form_state['values']['book_block_mode'];
   }
 
diff --git a/core/modules/ckeditor/src/CKEditorPluginConfigurableInterface.php b/core/modules/ckeditor/src/CKEditorPluginConfigurableInterface.php
index 619eb51..a5084fd 100644
--- a/core/modules/ckeditor/src/CKEditorPluginConfigurableInterface.php
+++ b/core/modules/ckeditor/src/CKEditorPluginConfigurableInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\ckeditor;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\Entity\Editor;
 
 /**
@@ -36,7 +37,7 @@
    *
    * @param array $form
    *   An empty form array to be populated with a configuration form, if any.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The state of the entire filter administration form.
    * @param \Drupal\editor\Entity\Editor $editor
    *   A configured text editor object.
@@ -44,6 +45,6 @@
    * @return array|FALSE
    *   A render array for the settings form, or FALSE if there is none.
    */
-  public function settingsForm(array $form, array &$form_state, Editor $editor);
+  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor);
 
 }
diff --git a/core/modules/ckeditor/src/CKEditorPluginManager.php b/core/modules/ckeditor/src/CKEditorPluginManager.php
index dab891d..289c906 100644
--- a/core/modules/ckeditor/src/CKEditorPluginManager.php
+++ b/core/modules/ckeditor/src/CKEditorPluginManager.php
@@ -8,6 +8,7 @@
 namespace Drupal\ckeditor;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -147,12 +148,12 @@ public function getButtons() {
    *
    * @param array &$form
    *   A reference to an associative array containing the structure of the form.
-   * @param array &$form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\editor\Entity\Editor $editor
    *   A configured text editor object.
    */
-  public function injectPluginSettingsForm(array &$form, array &$form_state, Editor $editor) {
+  public function injectPluginSettingsForm(array &$form, FormStateInterface $form_state, Editor $editor) {
     $definitions = $this->getDefinitions();
 
     foreach (array_keys($definitions) as $plugin_id) {
diff --git a/core/modules/ckeditor/src/Plugin/CKEditorPlugin/DrupalImage.php b/core/modules/ckeditor/src/Plugin/CKEditorPlugin/DrupalImage.php
index d9f411c..4a1329c 100644
--- a/core/modules/ckeditor/src/Plugin/CKEditorPlugin/DrupalImage.php
+++ b/core/modules/ckeditor/src/Plugin/CKEditorPlugin/DrupalImage.php
@@ -9,6 +9,7 @@
 
 use Drupal\ckeditor\CKEditorPluginBase;
 use Drupal\ckeditor\CKEditorPluginConfigurableInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\Entity\Editor;
 
 /**
@@ -66,7 +67,7 @@ public function getButtons() {
    * @see \Drupal\editor\Form\EditorImageDialog
    * @see editor_image_upload_settings_form()
    */
-  public function settingsForm(array $form, array &$form_state, Editor $editor) {
+  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
     form_load_include($form_state, 'inc', 'editor', 'editor.admin');
     $form['image_upload'] = editor_image_upload_settings_form($editor);
     $form['image_upload']['#attached']['library'][] = 'ckeditor/drupal.ckeditor.drupalimage.admin';
@@ -83,7 +84,7 @@ public function settingsForm(array $form, array &$form_state, Editor $editor) {
    * @see \Drupal\editor\Form\EditorImageDialog
    * @see editor_image_upload_settings_form()
    */
-  function validateImageUploadSettings(array $element, array &$form_state) {
+  function validateImageUploadSettings(array $element, FormStateInterface $form_state) {
     $settings = &$form_state['values']['editor']['settings']['plugins']['drupalimage']['image_upload'];
     $form_state['editor']->setImageUploadSettings($settings);
     unset($form_state['values']['editor']['settings']['plugins']['drupalimage']);
diff --git a/core/modules/ckeditor/src/Plugin/CKEditorPlugin/StylesCombo.php b/core/modules/ckeditor/src/Plugin/CKEditorPlugin/StylesCombo.php
index 2184cf2..963436d 100644
--- a/core/modules/ckeditor/src/Plugin/CKEditorPlugin/StylesCombo.php
+++ b/core/modules/ckeditor/src/Plugin/CKEditorPlugin/StylesCombo.php
@@ -10,6 +10,7 @@
 use Drupal\ckeditor\CKEditorPluginBase;
 use Drupal\ckeditor\CKEditorPluginConfigurableInterface;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\Entity\Editor;
 
 /**
@@ -66,7 +67,7 @@ public function getButtons() {
   /**
    * Implements \Drupal\ckeditor\Plugin\CKEditorPluginConfigurableInterface::settingsForm().
    */
-  public function settingsForm(array $form, array &$form_state, Editor $editor) {
+  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
     // Defaults.
     $config = array('styles' => '');
     $settings = $editor->getSettings();
@@ -94,7 +95,7 @@ public function settingsForm(array $form, array &$form_state, Editor $editor) {
   /**
    * #element_validate handler for the "styles" element in settingsForm().
    */
-  public function validateStylesValue(array $element, array &$form_state) {
+  public function validateStylesValue(array $element, FormStateInterface $form_state) {
     if ($this->generateStylesSetSetting($element['#value']) === FALSE) {
       form_error($element, $form_state, t('The provided list of styles is syntactically incorrect.'));
     }
diff --git a/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php b/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php
index d538b60..b377f73 100644
--- a/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php
+++ b/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\ckeditor\CKEditorPluginManager;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Render\Element;
 use Drupal\editor\Plugin\EditorBase;
@@ -127,7 +128,7 @@ public function getDefaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, EditorEntity $editor) {
+  public function settingsForm(array $form, FormStateInterface $form_state, EditorEntity $editor) {
     $settings = $editor->getSettings();
 
     $ckeditor_settings_toolbar = array(
@@ -234,7 +235,7 @@ public function settingsForm(array $form, array &$form_state, EditorEntity $edit
   /**
    * {@inheritdoc}
    */
-  public function settingsFormSubmit(array $form, array &$form_state) {
+  public function settingsFormSubmit(array $form, FormStateInterface $form_state) {
     // Modify the toolbar settings by reference. The values in
     // $form_state['values']['editor']['settings'] will be saved directly by
     // editor_form_filter_admin_format_submit().
diff --git a/core/modules/ckeditor/tests/modules/src/Plugin/CKEditorPlugin/LlamaContextualAndButton.php b/core/modules/ckeditor/tests/modules/src/Plugin/CKEditorPlugin/LlamaContextualAndButton.php
index 171e3b3..4c43cb7 100644
--- a/core/modules/ckeditor/tests/modules/src/Plugin/CKEditorPlugin/LlamaContextualAndButton.php
+++ b/core/modules/ckeditor/tests/modules/src/Plugin/CKEditorPlugin/LlamaContextualAndButton.php
@@ -11,6 +11,7 @@
 use Drupal\ckeditor\CKEditorPluginContextualInterface;
 use Drupal\ckeditor\CKEditorPluginConfigurableInterface;
 use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\Entity\Editor;
 
 /**
@@ -61,7 +62,7 @@ function getFile() {
   /**
    * Implements \Drupal\ckeditor\Plugin\CKEditorPluginConfigurableInterface::settingsForm().
    */
-  function settingsForm(array $form, array &$form_state, Editor $editor) {
+  function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
     // Defaults.
     $config = array('ultra_llama_mode' => FALSE);
     $settings = $editor->getSettings();
diff --git a/core/modules/color/color.module b/core/modules/color/color.module
index f0137cf..1f03e18 100644
--- a/core/modules/color/color.module
+++ b/core/modules/color/color.module
@@ -9,6 +9,7 @@
 use Drupal\Component\Utility\Environment;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -44,7 +45,7 @@ function color_theme() {
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function color_form_system_theme_settings_alter(&$form, &$form_state) {
+function color_form_system_theme_settings_alter(&$form, FormStateInterface $form_state) {
   if (isset($form_state['build_info']['args'][0]) && ($theme = $form_state['build_info']['args'][0]) && color_get_info($theme) && function_exists('gd_info')) {
     $form['color'] = array(
       '#type' => 'details',
@@ -166,7 +167,7 @@ function color_get_palette($theme, $default = FALSE) {
  * @see color_scheme_form_validate()
  * @see color_scheme_form_submit()
  */
-function color_scheme_form($complete_form, &$form_state, $theme) {
+function color_scheme_form($complete_form, FormStateInterface $form_state, $theme) {
   $base = drupal_get_path('module', 'color');
   $info = color_get_info($theme);
 
@@ -286,14 +287,14 @@ function template_preprocess_color_scheme_form(&$variables) {
  * @param string|bool $input
  *   The incoming input to populate the form element. If this is FALSE,
  *   the element's default value should be returned.
- * @param array $form_state
- *   A keyed array containing the current state of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @return string
  *   The data that will appear in the $form_state['values'] collection for this
  *   element. Return nothing to use the default.
  */
-function color_palette_color_value($element, $input = FALSE, $form_state = array()) {
+function color_palette_color_value($element, $input = FALSE, FormStateInterface $form_state) {
   // If we suspect a possible cross-site request forgery attack, only accept
   // hexadecimal CSS color strings from user input, to avoid problems when this
   // value is used in the JavaScript preview.
@@ -329,7 +330,7 @@ function color_valid_hexadecimal_string($color) {
  *
  * @see color_scheme_form_submit()
  */
-function color_scheme_form_validate($form, &$form_state) {
+function color_scheme_form_validate($form, FormStateInterface $form_state) {
   // Only accept hexadecimal CSS color strings to avoid XSS upon use.
   foreach ($form_state['values']['palette'] as $key => $color) {
     if (!color_valid_hexadecimal_string($color)) {
@@ -343,7 +344,7 @@ function color_scheme_form_validate($form, &$form_state) {
  *
  * @see color_scheme_form_validate()
  */
-function color_scheme_form_submit($form, &$form_state) {
+function color_scheme_form_submit($form, FormStateInterface $form_state) {
 
   // Get theme coloring info.
   if (!isset($form_state['values']['info'])) {
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index ab0df06..d5391f3 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -18,6 +18,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\entity\Entity\EntityViewDisplay;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
@@ -749,11 +750,13 @@ function comment_user_predelete($account) {
  *
  * @param \Drupal\comment\CommentInterface $comment
  *   The comment entity to preview.
+ * @param Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @return array
  *   An array as expected by drupal_render().
  */
-function comment_preview(CommentInterface $comment, array &$form_state) {
+function comment_preview(CommentInterface $comment, FormStateInterface $form_state) {
   $preview_build = array();
   $entity = $comment->getCommentedEntity();
 
diff --git a/core/modules/comment/config/install/views.view.comments_recent.yml b/core/modules/comment/config/install/views.view.comments_recent.yml
index f91f01a..674c8a8 100644
--- a/core/modules/comment/config/install/views.view.comments_recent.yml
+++ b/core/modules/comment/config/install/views.view.comments_recent.yml
@@ -3,6 +3,7 @@ status: true
 dependencies:
   module:
     - comment
+    - block
 id: comments_recent
 label: 'Recent comments'
 module: views
@@ -231,6 +232,7 @@ display:
       field_langcode: '***CURRENT_LANGUAGE***'
       field_langcode_add_to_query: null
   block_1:
+    provider: block
     display_plugin: block
     id: block_1
     display_title: Block
diff --git a/core/modules/comment/src/CommentForm.php b/core/modules/comment/src/CommentForm.php
index db4178d..9701e49 100644
--- a/core/modules/comment/src/CommentForm.php
+++ b/core/modules/comment/src/CommentForm.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -56,7 +57,7 @@ public function __construct(EntityManagerInterface $entity_manager, AccountInter
   /**
    * {@inheritdoc}
    */
-  protected function init(array &$form_state) {
+  protected function init(FormStateInterface $form_state) {
     $comment = $this->entity;
 
     // Make the comment inherit the current content language unless specifically
@@ -72,7 +73,7 @@ protected function init(array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::form().
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\comment\CommentInterface $comment */
     $comment = $this->entity;
     $entity = $this->entityManager->getStorage($comment->getCommentedEntityTypeId())->load($comment->getCommentedEntityId());
@@ -218,7 +219,7 @@ public function form(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::actions().
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $element = parent::actions($form, $form_state);
     /* @var \Drupal\comment\CommentInterface $comment */
     $comment = $this->entity;
@@ -255,7 +256,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::validate().
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
     $entity = $this->entity;
 
@@ -289,7 +290,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * Overrides EntityForm::buildEntity().
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     $comment = parent::buildEntity($form, $form_state);
     if (!empty($form_state['values']['date']) && $form_state['values']['date'] instanceOf DrupalDateTime) {
       $comment->setCreatedTime($form_state['values']['date']->getTimestamp());
@@ -304,7 +305,7 @@ public function buildEntity(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::submit().
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\comment\CommentInterface $comment */
     $comment = parent::submit($form, $form_state);
 
@@ -346,9 +347,9 @@ public function submit(array $form, array &$form_state) {
    * @param $form
    *   An associative array containing the structure of the form.
    * @param $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   *   The current state of the form.
    */
-  public function preview(array &$form, array &$form_state) {
+  public function preview(array &$form, FormStateInterface $form_state) {
     $comment = $this->entity;
     $form_state['comment_preview'] = comment_preview($comment, $form_state);
     $form_state['comment_preview']['#title'] = $this->t('Preview comment');
@@ -358,7 +359,7 @@ public function preview(array &$form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::save().
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $comment = $this->entity;
     $entity = $comment->getCommentedEntity();
     $field_name = $comment->getFieldName();
diff --git a/core/modules/comment/src/CommentTypeForm.php b/core/modules/comment/src/CommentTypeForm.php
index 43367a5..332e911 100644
--- a/core/modules/comment/src/CommentTypeForm.php
+++ b/core/modules/comment/src/CommentTypeForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -58,7 +59,7 @@ public function __construct(EntityManagerInterface $entity_manager, LoggerInterf
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $comment_type = $this->entity;
@@ -132,7 +133,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $comment_type = $this->entity;
     $status = $comment_type->save();
 
diff --git a/core/modules/comment/src/Form/CommentAdminOverview.php b/core/modules/comment/src/Form/CommentAdminOverview.php
index fd8f6dc..b1d3cb7 100644
--- a/core/modules/comment/src/Form/CommentAdminOverview.php
+++ b/core/modules/comment/src/Form/CommentAdminOverview.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -92,15 +93,15 @@ public function getFormID() {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $type
    *   The type of the overview form ('approval' or 'new').
    *
    * @return array
    *   The form structure.
    */
-  public function buildForm(array $form, array &$form_state, $type = 'new') {
+  public function buildForm(array $form, FormStateInterface $form_state, $type = 'new') {
 
     // Build an 'Update options' form.
     $form['options'] = array(
@@ -250,7 +251,7 @@ public function buildForm(array $form, array &$form_state, $type = 'new') {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state['values']['comments'] = array_diff($form_state['values']['comments'], array(0));
     // We can't execute any 'Update options' if no comments were selected.
     if (count($form_state['values']['comments']) == 0) {
@@ -261,7 +262,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $operation = $form_state['values']['operation'];
     $cids = $form_state['values']['comments'];
 
diff --git a/core/modules/comment/src/Form/CommentTypeDeleteForm.php b/core/modules/comment/src/Form/CommentTypeDeleteForm.php
index 85092db..64da7c4 100644
--- a/core/modules/comment/src/Form/CommentTypeDeleteForm.php
+++ b/core/modules/comment/src/Form/CommentTypeDeleteForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Entity\EntityManager;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\field\Entity\FieldStorageConfig;
 use Psr\Log\LoggerInterface;
@@ -111,7 +112,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $comments = $this->queryFactory->get('comment')->condition('comment_type', $this->entity->id())->execute();
     $entity_type = $this->entity->getTargetEntityTypeId();
     $caption = '';
@@ -140,7 +141,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     $form_state['redirect_route']['route_name'] = 'comment.type_list';
     drupal_set_message($this->t('Comment type %label has been deleted.', array('%label' => $this->entity->label())));
diff --git a/core/modules/comment/src/Form/ConfirmDeleteMultiple.php b/core/modules/comment/src/Form/ConfirmDeleteMultiple.php
index 5a0b062..39fe538 100644
--- a/core/modules/comment/src/Form/ConfirmDeleteMultiple.php
+++ b/core/modules/comment/src/Form/ConfirmDeleteMultiple.php
@@ -10,6 +10,7 @@
 use Drupal\comment\CommentStorageInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -82,7 +83,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $edit = $form_state['input'];
 
     $form['comments'] = array(
@@ -116,7 +117,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['confirm']) {
       $this->commentStorage->delete($this->comments);
       $count = count($form_state['values']['comments']);
diff --git a/core/modules/comment/src/Form/DeleteForm.php b/core/modules/comment/src/Form/DeleteForm.php
index b8cbae6..1ee7b4c 100644
--- a/core/modules/comment/src/Form/DeleteForm.php
+++ b/core/modules/comment/src/Form/DeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\comment\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides the comment delete confirmation form.
@@ -46,7 +47,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // Delete the comment and its replies.
     $this->entity->delete();
     drupal_set_message($this->t('The comment and all its replies have been deleted.'));
diff --git a/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php b/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php
index ad59c96..87ec9e7 100644
--- a/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php
+++ b/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Action\ConfigurableActionBase;
 use Drupal\comment\CommentInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Unpublishes a comment containing certain keywords.
@@ -49,7 +50,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['keywords'] = array(
       '#title' => t('Keywords'),
       '#type' => 'textarea',
@@ -62,7 +63,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['keywords'] = Tags::explode($form_state['values']['keywords']);
   }
 
diff --git a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
index be7bf53..e5ad723 100644
--- a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
+++ b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityViewBuilderInterface;
 use Drupal\Core\Entity\EntityFormBuilderInterface;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FormatterBase;
@@ -232,7 +233,7 @@ public function viewElements(FieldItemListInterface $items) {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
     $element['pager_id'] = array(
       '#type' => 'select',
diff --git a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
index 33a88b5..57e41d8 100644
--- a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
+++ b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
@@ -10,6 +10,7 @@
 use Drupal\comment\CommentManagerInterface;
 use Drupal\comment\Entity\CommentType;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\Field\FieldItemBase;
 use Drupal\Core\Session\AnonymousUserSession;
@@ -98,7 +99,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
 
     $settings = $this->getSettings();
@@ -188,7 +189,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element = array();
 
     // @todo Inject entity storage once typed-data supports container injection.
diff --git a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
index f9fdf73..87309c5 100644
--- a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
+++ b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
@@ -10,6 +10,7 @@
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a default comment widget.
@@ -27,7 +28,7 @@ class CommentWidget extends WidgetBase {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $entity = $items->getEntity();
 
     $element['status'] = array(
@@ -89,7 +90,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function massageFormValues(array $values, array $form, array &$form_state) {
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     // Add default values for statistics properties because we don't want to
     // have them in form.
     foreach ($values as &$value) {
diff --git a/core/modules/comment/src/Plugin/views/field/Comment.php b/core/modules/comment/src/Plugin/views/field/Comment.php
index 1a47a4a..25c001d 100644
--- a/core/modules/comment/src/Plugin/views/field/Comment.php
+++ b/core/modules/comment/src/Plugin/views/field/Comment.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -60,7 +61,7 @@ protected function defineOptions() {
   /**
    * Provide link-to-comment option
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_comment'] = array(
       '#title' => t('Link this field to its comment'),
       '#description' => t("Enable to override this field's links."),
diff --git a/core/modules/comment/src/Plugin/views/field/EntityLink.php b/core/modules/comment/src/Plugin/views/field/EntityLink.php
index f848210..c1dae39 100644
--- a/core/modules/comment/src/Plugin/views/field/EntityLink.php
+++ b/core/modules/comment/src/Plugin/views/field/EntityLink.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 
@@ -32,7 +33,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['teaser'] = array(
       '#type' => 'checkbox',
       '#title' => t('Show teaser-style link'),
diff --git a/core/modules/comment/src/Plugin/views/field/Link.php b/core/modules/comment/src/Plugin/views/field/Link.php
index a57ff12..4a3842e 100644
--- a/core/modules/comment/src/Plugin/views/field/Link.php
+++ b/core/modules/comment/src/Plugin/views/field/Link.php
@@ -8,6 +8,7 @@
 namespace Drupal\comment\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\views\ResultRow;
@@ -65,7 +66,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Text to display'),
diff --git a/core/modules/comment/src/Plugin/views/field/LinkEdit.php b/core/modules/comment/src/Plugin/views/field/LinkEdit.php
index f6137ad..7637143 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkEdit.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkEdit.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -25,7 +26,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['destination'] = array(
diff --git a/core/modules/comment/src/Plugin/views/field/NodeNewComments.php b/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
index 3366157..748291b 100644
--- a/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
+++ b/core/modules/comment/src/Plugin/views/field/NodeNewComments.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\comment\CommentInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\Numeric;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -82,7 +83,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_comment'] = array(
       '#title' => t('Link this field to new comments'),
       '#description' => t("Enable to override this field's links."),
diff --git a/core/modules/comment/src/Plugin/views/field/Username.php b/core/modules/comment/src/Plugin/views/field/Username.php
index c400144..b526dbc 100644
--- a/core/modules/comment/src/Plugin/views/field/Username.php
+++ b/core/modules/comment/src/Plugin/views/field/Username.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -39,7 +40,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_user'] = array(
       '#title' => t("Link this field to its user or an author's homepage"),
       '#type' => 'checkbox',
diff --git a/core/modules/comment/src/Plugin/views/row/CommentRow.php b/core/modules/comment/src/Plugin/views/row/CommentRow.php
index 2d34728..5256b56 100644
--- a/core/modules/comment/src/Plugin/views/row/CommentRow.php
+++ b/core/modules/comment/src/Plugin/views/row/CommentRow.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\EntityRow;
 
 /**
@@ -31,7 +32,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['links'] = array(
diff --git a/core/modules/comment/src/Plugin/views/row/Rss.php b/core/modules/comment/src/Plugin/views/row/Rss.php
index 8b8fc4a..d24eefe 100644
--- a/core/modules/comment/src/Plugin/views/row/Rss.php
+++ b/core/modules/comment/src/Plugin/views/row/Rss.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\RowPluginBase;
 
 /**
@@ -36,7 +37,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['view_mode'] = array(
diff --git a/core/modules/comment/src/Plugin/views/wizard/Comment.php b/core/modules/comment/src/Plugin/views/wizard/Comment.php
index c2c4ff4..5227f39 100644
--- a/core/modules/comment/src/Plugin/views/wizard/Comment.php
+++ b/core/modules/comment/src/Plugin/views/wizard/Comment.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\comment\Plugin\views\wizard;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\wizard\WizardPluginBase;
 
 /**
@@ -73,7 +74,7 @@ protected function rowStyleOptions() {
     return $options;
   }
 
-  protected function buildFormStyle(array &$form, array &$form_state, $type) {
+  protected function buildFormStyle(array &$form, FormStateInterface $form_state, $type) {
     parent::buildFormStyle($form, $form_state, $type);
     $style_form =& $form['displays'][$type]['options']['style'];
     // Some style plugins don't support row plugins so stop here if that's the
@@ -101,7 +102,7 @@ protected function buildFormStyle(array &$form, array &$form_state, $type) {
   /**
    * {@inheritdoc}
    */
-  protected function pageDisplayOptions(array $form, array &$form_state) {
+  protected function pageDisplayOptions(array $form, FormStateInterface $form_state) {
     $display_options = parent::pageDisplayOptions($form, $form_state);
     $row_plugin = isset($form_state['values']['page']['style']['row_plugin']) ? $form_state['values']['page']['style']['row_plugin'] : NULL;
     $row_options = isset($form_state['values']['page']['style']['row_options']) ? $form_state['values']['page']['style']['row_options'] : array();
@@ -112,7 +113,7 @@ protected function pageDisplayOptions(array $form, array &$form_state) {
   /**
    * Overrides Drupal\views\Plugin\views\wizard\WizardPluginBase::blockDisplayOptions().
    */
-  protected function blockDisplayOptions(array $form, array &$form_state) {
+  protected function blockDisplayOptions(array $form, FormStateInterface $form_state) {
     $display_options = parent::blockDisplayOptions($form, $form_state);
     $row_plugin = isset($form_state['values']['block']['style']['row_plugin']) ? $form_state['values']['block']['style']['row_plugin'] : NULL;
     $row_options = isset($form_state['values']['block']['style']['row_options']) ? $form_state['values']['block']['style']['row_options'] : array();
diff --git a/core/modules/config/src/Form/ConfigExportForm.php b/core/modules/config/src/Form/ConfigExportForm.php
index c351818..e76a56c 100644
--- a/core/modules/config/src/Form/ConfigExportForm.php
+++ b/core/modules/config/src/Form/ConfigExportForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\config\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines the configuration export form.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['description'] = array(
       '#markup' => '<p>' . $this->t('Use the export button below to download your site configuration.') . '</p>',
     );
@@ -38,7 +39,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route']['route_name'] = 'config.export_download';
   }
 
diff --git a/core/modules/config/src/Form/ConfigImportForm.php b/core/modules/config/src/Form/ConfigImportForm.php
index 97d039e..00315e1 100644
--- a/core/modules/config/src/Form/ConfigImportForm.php
+++ b/core/modules/config/src/Form/ConfigImportForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Archiver\ArchiveTar;
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -53,7 +54,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['description'] = array(
       '#markup' => '<p>' . $this->t('Use the upload button below.') . '</p>',
     );
@@ -73,7 +74,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $file_upload = $this->getRequest()->files->get('files[import_tarball]', NULL, TRUE);
     if ($file_upload && $file_upload->isValid()) {
       $form_state['values']['import_tarball'] = $file_upload->getRealPath();
@@ -86,7 +87,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($path = $form_state['values']['import_tarball']) {
       $this->configStorage->deleteAll();
       try {
diff --git a/core/modules/config/src/Form/ConfigSingleExportForm.php b/core/modules/config/src/Form/ConfigSingleExportForm.php
index 14255b5..28d1069 100644
--- a/core/modules/config/src/Form/ConfigSingleExportForm.php
+++ b/core/modules/config/src/Form/ConfigSingleExportForm.php
@@ -12,6 +12,8 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -73,7 +75,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $config_type = NULL, $config_name = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $config_type = NULL, $config_name = NULL) {
     foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
       if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
         $this->definitions[$entity_type] = $definition;
@@ -121,10 +123,10 @@ public function buildForm(array $form, array &$form_state, $config_type = NULL,
       '#suffix' => '</div>',
     );
     if ($config_type && $config_name) {
-      $fake_form_state = array('values' => array(
+      $fake_form_state = new FormState(array('values' => array(
         'config_type' => $config_type,
         'config_name' => $config_name,
-      ));
+      )));
       $form['export'] = $this->updateExport($form, $fake_form_state);
     }
     return $form;
@@ -133,7 +135,7 @@ public function buildForm(array $form, array &$form_state, $config_type = NULL,
   /**
    * Handles switching the configuration type selector.
    */
-  public function updateConfigurationType($form, &$form_state) {
+  public function updateConfigurationType($form, FormStateInterface $form_state) {
     $form['config_name']['#options'] = $this->findConfiguration($form_state['values']['config_type']);
     return $form['config_name'];
   }
@@ -141,7 +143,7 @@ public function updateConfigurationType($form, &$form_state) {
   /**
    * Handles switching the export textarea.
    */
-  public function updateExport($form, &$form_state) {
+  public function updateExport($form, FormStateInterface $form_state) {
     // Determine the full config name for the selected config entity.
     if ($form_state['values']['config_type'] !== 'system.simple') {
       $definition = $this->entityManager->getDefinition($form_state['values']['config_type']);
@@ -197,7 +199,7 @@ protected function findConfiguration($config_type) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Nothing to submit.
   }
 
diff --git a/core/modules/config/src/Form/ConfigSingleImportForm.php b/core/modules/config/src/Form/ConfigSingleImportForm.php
index 0793c58..faff0e9 100644
--- a/core/modules/config/src/Form/ConfigSingleImportForm.php
+++ b/core/modules/config/src/Form/ConfigSingleImportForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -114,7 +115,7 @@ public function getQuestion() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // When this is the confirmation step fall through to the confirmation form.
     if ($this->data) {
       return parent::buildForm($form, $form_state);
@@ -177,7 +178,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // The confirmation step needs no additional validation.
     if ($this->data) {
       return;
@@ -232,7 +233,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // If this form has not yet been confirmed, store the values and rebuild.
     if (!$this->data) {
       $form_state['rebuild'] = TRUE;
diff --git a/core/modules/config/src/Form/ConfigSync.php b/core/modules/config/src/Form/ConfigSync.php
index 7c48dd5..a93c0ff 100644
--- a/core/modules/config/src/Form/ConfigSync.php
+++ b/core/modules/config/src/Form/ConfigSync.php
@@ -17,6 +17,7 @@
 use Drupal\Core\Config\ConfigManagerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\Core\Config\StorageComparer;
 use Drupal\Core\Routing\UrlGeneratorInterface;
@@ -152,7 +153,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array(
       '#type' => 'submit',
@@ -270,7 +271,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $config_importer = new ConfigImporter(
       $form_state['storage_comparer'],
       $this->eventDispatcher,
diff --git a/core/modules/config/tests/config_test/src/ConfigTestForm.php b/core/modules/config/tests/config_test/src/ConfigTestForm.php
index 8a680b2..cbe4c6f 100644
--- a/core/modules/config/tests/config_test/src/ConfigTestForm.php
+++ b/core/modules/config/tests/config_test/src/ConfigTestForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\config_test;
 
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for the test config edit forms.
@@ -15,9 +16,9 @@
 class ConfigTestForm extends EntityForm {
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::form().
+   * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $entity = $this->entity;
@@ -67,9 +68,9 @@ public function form(array $form, array &$form_state) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::save().
+   * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
     $status = $entity->save();
 
diff --git a/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php b/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php
index 63cdfd6..d344a4e 100644
--- a/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php
+++ b/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php
@@ -8,6 +8,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message(String::format('%label configuration has been deleted.', array('%label' => $this->entity->label())));
     $form_state['redirect_route'] = $this->getCancelUrl();
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationAddForm.php b/core/modules/config_translation/src/Form/ConfigTranslationAddForm.php
index 9556be2..1930c3b 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationAddForm.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationAddForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\config_translation\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
     $form = parent::buildForm($form, $form_state, $request, $plugin_id, $langcode);
     $form['#title'] = $this->t('Add @language translation for %label', array(
       '%label' => $this->mapper->getTitle(),
@@ -36,7 +37,7 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
     drupal_set_message($this->t('Successfully saved @language translation.', array('@language' => $this->language->name)));
   }
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php b/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php
index e064b1a..fc9c730 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -115,7 +116,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
     $mapper->populateFromRequest($request);
@@ -133,7 +134,7 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     foreach ($this->mapper->getConfigNames() as $name) {
       $this->languageManager->getLanguageConfigOverride($this->language->id, $name)->delete();
     }
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationEditForm.php b/core/modules/config_translation/src/Form/ConfigTranslationEditForm.php
index 565d07a..91e4797 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationEditForm.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationEditForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\config_translation\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
     $form = parent::buildForm($form, $form_state, $request, $plugin_id, $langcode);
     $form['#title'] = $this->t('Edit @language translation for %label', array(
       '%label' => $this->mapper->getTitle(),
@@ -36,7 +37,7 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
     drupal_set_message($this->t('Successfully updated @language translation.', array('@language' => $this->language->name)));
   }
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
index 5b6125a..29ed2c9 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\BaseFormIdInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\language\Config\LanguageConfigOverride;
 use Drupal\language\ConfigurableLanguageManagerInterface;
@@ -138,8 +139,8 @@ public function getBaseFormID() {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   (optional) Page request object.
    * @param string $plugin_id
@@ -155,7 +156,7 @@ public function getBaseFormID() {
    *   Throws an exception if the language code provided as a query parameter in
    *   the request does not match an active language.
    */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
     $mapper->populateFromRequest($request);
@@ -214,7 +215,7 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_values = $form_state['values']['config_names'];
 
     // For the form submission handling, use the raw data.
diff --git a/core/modules/config_translation/src/FormElement/DateFormat.php b/core/modules/config_translation/src/FormElement/DateFormat.php
index 2e089cb..d00a71e 100644
--- a/core/modules/config_translation/src/FormElement/DateFormat.php
+++ b/core/modules/config_translation/src/FormElement/DateFormat.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\ReplaceCommand;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\TypedData\DataDefinitionInterface;
@@ -46,7 +47,7 @@ public function getFormElement(DataDefinitionInterface $definition, LanguageInte
    *
    * @param array $form
    *   Form API array structure.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   Form state information.
    *
    * @return AjaxResponse
@@ -54,7 +55,7 @@ public function getFormElement(DataDefinitionInterface $definition, LanguageInte
    *   the given format cannot be identified or was empty, the response will
    *   be empty as well.
    */
-  public static function ajaxSample(array $form, array $form_state) {
+  public static function ajaxSample(array $form, FormStateInterface $form_state) {
     $response = new AjaxResponse();
 
     $format_value = NestedArray::getValue($form_state['values'], $form_state['triggering_element']['#array_parents']);
diff --git a/core/modules/config_translation/tests/modules/config_translation_test/config_translation_test.module b/core/modules/config_translation/tests/modules/config_translation_test/config_translation_test.module
index d38be97..582be7c 100644
--- a/core/modules/config_translation/tests/modules/config_translation_test/config_translation_test.module
+++ b/core/modules/config_translation/tests/modules/config_translation_test/config_translation_test.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Extension\Extension;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Implements hook_system_info_alter().
@@ -47,7 +48,7 @@ function config_translation_test_config_translation_info_alter(&$info) {
  *
  * @see \Drupal\config_translation\Form\ConfigTranslationFormBase
  */
-function config_translation_test_form_config_translation_form_alter(&$form, &$form_state) {
+function config_translation_test_form_config_translation_form_alter(&$form, FormStateInterface $form_state) {
   if (\Drupal::state()->get('config_translation_test_alter_form_alter')) {
     $form['#base_altered'] = TRUE;
   }
@@ -60,7 +61,7 @@ function config_translation_test_form_config_translation_form_alter(&$form, &$fo
  *
  * @see \Drupal\config_translation\Form\ConfigTranslationAddForm
  */
-function config_translation_test_form_config_translation_add_form_alter(&$form, &$form_state) {
+function config_translation_test_form_config_translation_add_form_alter(&$form, FormStateInterface $form_state) {
   if (\Drupal::state()->get('config_translation_test_alter_form_alter')) {
     $form['#altered'] = TRUE;
   }
@@ -77,7 +78,7 @@ function config_translation_test_form_config_translation_add_form_alter(&$form,
  *
  * @see \Drupal\config_translation\Form\ConfigTranslationEditForm
  */
-function config_translation_test_form_config_translation_edit_form_alter(&$form, &$form_state) {
+function config_translation_test_form_config_translation_edit_form_alter(&$form, FormStateInterface $form_state) {
   if (\Drupal::state()->get('config_translation_test_alter_form_alter')) {
     $form['#altered'] = TRUE;
   }
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index e8485c1..bee5dcf 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -5,6 +5,7 @@
  * Enables the use of personal and site-wide contact forms.
  */
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -162,7 +163,7 @@ function contact_mail($key, &$message, $params) {
  *
  * @see \Drupal\user\ProfileForm::form()
  */
-function contact_form_user_form_alter(&$form, &$form_state) {
+function contact_form_user_form_alter(&$form, FormStateInterface $form_state) {
   $form['contact'] = array(
     '#type' => 'details',
     '#title' => t('Contact settings'),
@@ -185,7 +186,7 @@ function contact_form_user_form_alter(&$form, &$form_state) {
 /**
  * Submit callback for the user profile form to save the contact page setting.
  */
-function contact_user_profile_form_submit($form, &$form_state) {
+function contact_user_profile_form_submit($form, FormStateInterface $form_state) {
   $account = $form_state['controller']->getEntity();
   if ($account->id() && isset($form_state['values']['contact'])) {
     \Drupal::service('user.data')->set('contact', $account->id(), 'enabled', (int) $form_state['values']['contact']);
@@ -199,7 +200,7 @@ function contact_user_profile_form_submit($form, &$form_state) {
  *
  * @see user_admin_settings()
  */
-function contact_form_user_admin_settings_alter(&$form, &$form_state) {
+function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form_state) {
   $form['contact'] = array(
     '#type' => 'details',
     '#title' => t('Contact settings'),
@@ -221,7 +222,7 @@ function contact_form_user_admin_settings_alter(&$form, &$form_state) {
  *
  * @see contact_form_user_admin_settings_alter()
  */
-function contact_form_user_admin_settings_submit($form, &$form_state) {
+function contact_form_user_admin_settings_submit($form, FormStateInterface $form_state) {
   \Drupal::config('contact.settings')
     ->set('user_default_enabled', $form_state['values']['contact_default_status'])
     ->save();
diff --git a/core/modules/contact/src/CategoryForm.php b/core/modules/contact/src/CategoryForm.php
index fd315a6..df91084 100644
--- a/core/modules/contact/src/CategoryForm.php
+++ b/core/modules/contact/src/CategoryForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Base form for category edit forms.
@@ -18,7 +19,7 @@ class CategoryForm extends EntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $category = $this->entity;
@@ -72,7 +73,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     // Validate and each email recipient.
@@ -90,7 +91,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $category = $this->entity;
     $status = $category->save();
     $contact_settings = $this->config('contact.settings');
diff --git a/core/modules/contact/src/Form/CategoryDeleteForm.php b/core/modules/contact/src/Form/CategoryDeleteForm.php
index 9117a75..5fddb08 100644
--- a/core/modules/contact/src/Form/CategoryDeleteForm.php
+++ b/core/modules/contact/src/Form/CategoryDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\contact\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message($this->t('Category %label has been deleted.', array('%label' => $this->entity->label())));
     watchdog('contact', 'Category %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/contact/src/MessageForm.php b/core/modules/contact/src/MessageForm.php
index d289f38..30ac410 100644
--- a/core/modules/contact/src/MessageForm.php
+++ b/core/modules/contact/src/MessageForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Flood\FloodInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
@@ -72,7 +73,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $user = $this->currentUser();
     $message = $this->entity;
     $form = parent::form($form, $form_state, $message);
@@ -150,7 +151,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function actions(array $form, array &$form_state) {
+  public function actions(array $form, FormStateInterface $form_state) {
     $elements = parent::actions($form, $form_state);
     $elements['submit']['#value'] = $this->t('Send message');
     $elements['preview'] = array(
@@ -169,7 +170,7 @@ public function actions(array $form, array &$form_state) {
   /**
    * Form submission handler for the 'preview' action.
    */
-  public function preview(array $form, array &$form_state) {
+  public function preview(array $form, FormStateInterface $form_state) {
     $message = $this->entity;
     $message->preview = TRUE;
     $form_state['rebuild'] = TRUE;
@@ -178,7 +179,7 @@ public function preview(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $user = $this->currentUser();
 
     $language_interface = $this->languageManager->getCurrentLanguage();
@@ -271,7 +272,7 @@ public function save(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function init(array &$form_state) {
+  protected function init(FormStateInterface $form_state) {
     $message = $this->entity;
 
     // Make the message inherit the current content language unless specifically
diff --git a/core/modules/contact/src/Plugin/views/field/ContactLink.php b/core/modules/contact/src/Plugin/views/field/ContactLink.php
index 15313e0..8b0ce91 100644
--- a/core/modules/contact/src/Plugin/views/field/ContactLink.php
+++ b/core/modules/contact/src/Plugin/views/field/ContactLink.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\Plugin\views\field\Link;
 use Drupal\views\ResultRow;
@@ -84,7 +85,7 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['text']['#title'] = t('Link label');
     $form['text']['#required'] = TRUE;
diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc
index 7e7e790..9b33f0e 100644
--- a/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Element;
 use Drupal\field\FieldInstanceConfigInterface;
@@ -60,7 +61,7 @@ function content_translation_field_sync_widget(FieldDefinitionInterface $field)
 /**
  * (proxied) Implements hook_form_FORM_ID_alter().
  */
-function _content_translation_form_language_content_settings_form_alter(array &$form, array &$form_state) {
+function _content_translation_form_language_content_settings_form_alter(array &$form, FormStateInterface $form_state) {
   // Inject into the content language settings the translation settings if the
   // user has the required permission.
   if (!\Drupal::currentUser()->hasPermission('administer content translation')) {
@@ -254,7 +255,7 @@ function _content_translation_preprocess_language_content_settings_table(&$varia
  *
  * @see content_translation_admin_settings_form_submit()
  */
-function content_translation_form_language_content_settings_validate(array $form, array &$form_state) {
+function content_translation_form_language_content_settings_validate(array $form, FormStateInterface $form_state) {
   $settings = &$form_state['values']['settings'];
   foreach ($settings as $entity_type => $entity_settings) {
     foreach ($entity_settings as $bundle => $bundle_settings) {
@@ -284,7 +285,7 @@ function content_translation_form_language_content_settings_validate(array $form
  *
  * @see content_translation_admin_settings_form_validate()
  */
-function content_translation_form_language_content_settings_submit(array $form, array &$form_state) {
+function content_translation_form_language_content_settings_submit(array $form, FormStateInterface $form_state) {
   $entity_types = $form_state['values']['entity_types'];
   $settings = &$form_state['values']['settings'];
 
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 4fbd597..c79213a 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -9,6 +9,7 @@
 use Drupal\Core\Entity\EntityFormInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\field\Entity\FieldInstanceConfig;
@@ -203,9 +204,9 @@ function content_translation_entity_operation_alter(array &$operations, \Drupal\
 }
 
 /**
- * Implements hook_menu_link_defaults_alter().
+ * Implements hook_menu_links_discovered_alter().
  */
-function content_translation_menu_link_defaults_alter(array &$links) {
+function content_translation_menu_links_discovered_alter(array &$links) {
   // Clarify where translation settings are located.
   $links['language.content_settings_page']['title'] = 'Content language and translation';
   $links['language.content_settings_page']['description'] = 'Configure language and translation support for content.';
@@ -366,8 +367,8 @@ function content_translation_controller($entity_type_id) {
 /**
  * Returns the entity form for the given form.
  *
- * @param array $form_state
- *   The form state array holding the entity form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current form state holding the entity form.
  *
  * @return \Drupal\Core\Entity\EntityFormInterface;
  *   An instance of the content translation form interface or FALSE if not an
@@ -375,7 +376,7 @@ function content_translation_controller($entity_type_id) {
  *
  * @todo Move to \Drupal\content_translation\ContentTranslationManager.
  */
-function content_translation_form_controller(array $form_state) {
+function content_translation_form_controller($form_state) {
   return isset($form_state['controller']) && $form_state['controller'] instanceof EntityFormInterface ? $form_state['controller'] : FALSE;
 }
 
@@ -458,7 +459,7 @@ function content_translation_permission() {
 /**
  * Implements hook_form_alter().
  */
-function content_translation_form_alter(array &$form, array &$form_state) {
+function content_translation_form_alter(array &$form, FormStateInterface $form_state) {
   $form_controller = content_translation_form_controller($form_state);
   $entity = $form_controller ? $form_controller->getEntity() : NULL;
 
@@ -644,7 +645,7 @@ function content_translation_entity_extra_field_info() {
 /**
  * Implements hook_form_FORM_ID_alter() for 'field_ui_instance_edit_form'.
  */
-function content_translation_form_field_ui_field_instance_edit_form_alter(array &$form, array &$form_state) {
+function content_translation_form_field_ui_field_instance_edit_form_alter(array &$form, FormStateInterface $form_state) {
   $instance = $form_state['instance'];
   $bundle_is_translatable = content_translation_enabled($instance->entity_type, $instance->bundle);
 
@@ -722,10 +723,10 @@ function content_translation_element_info_alter(&$type) {
  *   The bundle of the entity being configured for translation.
  * @param array $form
  *   The configuration form array.
- * @param array $form_state
- *   The configuration form state array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  */
-function content_translation_enable_widget($entity_type, $bundle, array &$form, array &$form_state) {
+function content_translation_enable_widget($entity_type, $bundle, array &$form, FormStateInterface $form_state) {
   $key = $form_state['content_translation']['key'];
   if (!isset($form_state['language'][$key])) {
     $form_state['language'][$key] = array();
@@ -745,7 +746,7 @@ function content_translation_enable_widget($entity_type, $bundle, array &$form,
  * @return
  *   Processed language configuration element.
  */
-function content_translation_language_configuration_element_process(array $element, array &$form_state, array &$form) {
+function content_translation_language_configuration_element_process(array $element, FormStateInterface $form_state, array &$form) {
   if (empty($element['#content_translation_skip_alter']) && \Drupal::currentUser()->hasPermission('administer content translation')) {
     $form_state['content_translation']['key'] = $element['#name'];
     $context = $form_state['language'][$element['#name']];
@@ -772,7 +773,7 @@ function content_translation_language_configuration_element_process(array $eleme
  *
  * @see content_translation_language_configuration_element_submit()
  */
-function content_translation_language_configuration_element_validate($element, array &$form_state, array $form) {
+function content_translation_language_configuration_element_validate($element, FormStateInterface $form_state, array $form) {
   $key = $form_state['content_translation']['key'];
   $values = $form_state['values'][$key];
   if (!$values['language_show'] && $values['content_translation'] && \Drupal::languageManager()->isLanguageLocked($values['langcode'])) {
@@ -793,7 +794,7 @@ function content_translation_language_configuration_element_validate($element, a
  *
  * @see content_translation_language_configuration_element_validate()
  */
-function content_translation_language_configuration_element_submit(array $form, array &$form_state) {
+function content_translation_language_configuration_element_submit(array $form, FormStateInterface $form_state) {
   $key = $form_state['content_translation']['key'];
   $context = $form_state['language'][$key];
   $enabled = $form_state['values'][$key]['content_translation'];
@@ -808,7 +809,7 @@ function content_translation_language_configuration_element_submit(array $form,
 /**
  * Implements hook_form_FORM_ID_alter() for language_content_settings_form().
  */
-function content_translation_form_language_content_settings_form_alter(array &$form, array &$form_state) {
+function content_translation_form_language_content_settings_form_alter(array &$form, FormStateInterface $form_state) {
   module_load_include('inc', 'content_translation', 'content_translation.admin');
   _content_translation_form_language_content_settings_form_alter($form, $form_state);
 }
diff --git a/core/modules/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php
index 7510d2e..d14a945 100644
--- a/core/modules/content_translation/src/ContentTranslationHandler.php
+++ b/core/modules/content_translation/src/ContentTranslationHandler.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Element;
 
@@ -75,14 +76,14 @@ public function getTranslationAccess(EntityInterface $entity, $op) {
   /**
    * {@inheritdoc}
    */
-  public function getSourceLangcode(array $form_state) {
+  public function getSourceLangcode($form_state) {
     return isset($form_state['content_translation']['source']) ? $form_state['content_translation']['source']->id : FALSE;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity) {
+  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
     $form_controller = content_translation_form_controller($form_state);
     $form_langcode = $form_controller->getFormLangcode($form_state);
     $entity_langcode = $entity->getUntranslated()->language()->id;
@@ -371,7 +372,7 @@ protected function addTranslatabilityClue(&$element) {
    *
    * @see \Drupal\content_translation\ContentTranslationHandler::entityFormAlter()
    */
-  public function entityFormEntityBuild($entity_type, EntityInterface $entity, array $form, array &$form_state) {
+  public function entityFormEntityBuild($entity_type, EntityInterface $entity, array $form, FormStateInterface $form_state) {
     $form_controller = content_translation_form_controller($form_state);
     $form_langcode = $form_controller->getFormLangcode($form_state);
 
@@ -410,7 +411,7 @@ public function entityFormEntityBuild($entity_type, EntityInterface $entity, arr
    *
    * Validates the submitted content translation metadata.
    */
-  function entityFormValidate($form, &$form_state) {
+  function entityFormValidate($form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['content_translation'])) {
       $translation = $form_state['values']['content_translation'];
       // Validate the "authored by" field.
@@ -429,7 +430,7 @@ function entityFormValidate($form, &$form_state) {
    *
    * Takes care of the source language change.
    */
-  public function entityFormSourceChange($form, &$form_state) {
+  public function entityFormSourceChange($form, FormStateInterface $form_state) {
     $form_controller = content_translation_form_controller($form_state);
     $entity = $form_controller->getEntity();
     $source = $form_state['values']['source_langcode']['source'];
@@ -445,7 +446,7 @@ public function entityFormSourceChange($form, &$form_state) {
    *
    * Takes care of entity deletion.
    */
-  function entityFormDelete($form, &$form_state) {
+  function entityFormDelete($form, FormStateInterface $form_state) {
     $form_controller = content_translation_form_controller($form_state);
     $entity = $form_controller->getEntity();
     if (count($entity->getTranslationLanguages()) > 1) {
@@ -458,7 +459,7 @@ function entityFormDelete($form, &$form_state) {
    *
    * Takes care of content translation deletion.
    */
-  function entityFormDeleteTranslation($form, &$form_state) {
+  function entityFormDeleteTranslation($form, FormStateInterface $form_state) {
     $form_controller = content_translation_form_controller($form_state);
     $entity = $form_controller->getEntity();
     $path = $entity->getSystemPath('drupal:content-translation-overview');
diff --git a/core/modules/content_translation/src/ContentTranslationHandlerInterface.php b/core/modules/content_translation/src/ContentTranslationHandlerInterface.php
index c41fd27..67c4d0d 100644
--- a/core/modules/content_translation/src/ContentTranslationHandlerInterface.php
+++ b/core/modules/content_translation/src/ContentTranslationHandlerInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\content_translation;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Interface for providing content translation.
@@ -37,13 +38,13 @@ public function getTranslationAccess(EntityInterface $entity, $op);
   /**
    * Retrieves the source language for the translation being created.
    *
-   * @param array $form_state
-   *   The form state array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return string
    *   The source language code.
    */
-  public function getSourceLangcode(array $form_state);
+  public function getSourceLangcode($form_state);
 
   /**
    * Marks translations as outdated.
@@ -61,11 +62,11 @@ public function retranslate(EntityInterface $entity, $langcode = NULL);
    *
    * @param array $form
    *   The entity form to be altered to provide the translation workflow.
-   * @param array $form_state
-   *   The form state array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity being created or edited.
    */
-  public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity);
+  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity);
 
 }
diff --git a/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php b/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php
index af2d3af..a265124 100644
--- a/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php
+++ b/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\content_translation\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $_entity_type_id = NULL, $language = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $_entity_type_id = NULL, $language = NULL) {
     $this->entity = $this->getRequest()->attributes->get($_entity_type_id);
     $this->language = language_load($language);
     return parent::buildForm($form, $form_state);
@@ -69,7 +70,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Remove the translated values.
     $this->entity->removeTranslation($this->language->id);
     $this->entity->save();
diff --git a/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php b/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php
index 2a6ec79..9d234ab 100644
--- a/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php
+++ b/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\content_translation\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\views\ResultRow;
@@ -32,7 +33,7 @@ protected function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Text to display'),
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php
index 556e419..76fa6be 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationSettingsTest.php
@@ -44,7 +44,7 @@ function setUp() {
    * Tests that the settings UI works as expected.
    */
   function testSettingsUI() {
-    // Check for the content_translation_menu_link_defaults_alter() changes.
+    // Check for the content_translation_menu_links_discovered_alter() changes.
     $this->drupalGet('admin/config');
     $this->assertLink('Content language and translation');
     $this->assertText('Configure language and translation support for content.');
diff --git a/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php b/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
index aff000c..dd8c990 100644
--- a/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
+++ b/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 
@@ -37,7 +38,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $all_fields = $this->view->display_handler->getFieldLabels();
     // Offer to include only those fields that follow this one.
     $field_options = array_slice($all_fields, 0, array_search($this->options['id'], array_keys($all_fields)));
diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module
index b5f98dd..e70bad3 100644
--- a/core/modules/datetime/datetime.module
+++ b/core/modules/datetime/datetime.module
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Template\Attribute;
 use Drupal\datetime\DateHelper;
@@ -119,10 +120,10 @@ function datetime_theme() {
  *
  * @param array $element
  *   The form element whose value is being validated.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
-function datetime_datetime_widget_validate(&$element, &$form_state) {
+function datetime_datetime_widget_validate(&$element, FormStateInterface $form_state) {
   if (!form_get_errors($form_state)) {
     $input_exists = FALSE;
     $input = NestedArray::getValue($form_state['values'], $element['#parents'], $input_exists);
@@ -157,10 +158,10 @@ function datetime_datetime_widget_validate(&$element, &$form_state) {
  *
  * @param array $element
  *   The form element whose value is being validated.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
-function datetime_datelist_widget_validate(&$element, &$form_state) {
+function datetime_datelist_widget_validate(&$element, FormStateInterface $form_state) {
   if (!form_get_errors($form_state)) {
     $input_exists = FALSE;
     $input = NestedArray::getValue($form_state['values'], $element['#parents'], $input_exists);
@@ -352,13 +353,13 @@ function template_preprocess_datetime_wrapper(&$variables) {
  *
  * @param array $element
  *   The form element whose value is being processed.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  *
  * @return array
  *   The form element whose value has been processed.
  */
-function datetime_datetime_form_process($element, &$form_state) {
+function datetime_datetime_form_process($element, FormStateInterface $form_state) {
   $format_settings = array();
   // The value callback has populated the #value array.
   $date = !empty($element['#value']['object']) ? $element['#value']['object'] : NULL;
@@ -527,10 +528,10 @@ function form_type_datetime_value($element, $input = FALSE) {
  *
  * @param array $element
  *   The form element whose value is being validated.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
-function datetime_datetime_validate($element, &$form_state) {
+function datetime_datetime_validate($element, FormStateInterface $form_state) {
 
   $input_exists = FALSE;
   $input = NestedArray::getValue($form_state['values'], $element['#parents'], $input_exists);
@@ -675,10 +676,10 @@ function datetime_format_example($format) {
  *
  * @param array $element
  *   The form element whose value is being processed.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
-function datetime_datelist_form_process($element, &$form_state) {
+function datetime_datelist_form_process($element, FormStateInterface $form_state) {
 
   // Load translated date part labels from the appropriate calendar plugin.
   $date_helper = new DateHelper();
@@ -788,14 +789,12 @@ function datetime_datelist_form_process($element, &$form_state) {
  * @param array $element
  *   The element being processed.
  * @param array|false $input
- *
- * @param array $form_state
- *   (optional) The current state of the form.  Defaults to an empty array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @return array
- *
  */
-function form_type_datelist_value($element, $input = FALSE, &$form_state = array()) {
+function form_type_datelist_value($element, $input = FALSE, FormStateInterface $form_state) {
   $parts = $element['#date_part_order'];
   $increment = $element['#date_increment'];
 
@@ -871,10 +870,10 @@ function form_type_datelist_value($element, $input = FALSE, &$form_state = array
  *
  * @param array $element
  *   The element being processed.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  */
-function datetime_datelist_validate($element, &$form_state) {
+function datetime_datelist_validate($element, FormStateInterface $form_state) {
   $input_exists = FALSE;
   $input = NestedArray::getValue($form_state['values'], $element['#parents'], $input_exists);
   if ($input_exists) {
@@ -1001,7 +1000,7 @@ function datetime_range_years($string, $date = NULL) {
 /**
  * Implements hook_form_BASE_FORM_ID_alter() for node forms.
  */
-function datetime_form_node_form_alter(&$form, &$form_state, $form_id) {
+function datetime_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   // Alter the 'Authored on' date to use datetime.
   $form['created']['#type'] = 'datetime';
   $date_format = entity_load('date_format', 'html_date')->getPattern();
@@ -1013,7 +1012,7 @@ function datetime_form_node_form_alter(&$form, &$form_state, $form_id) {
 /**
  * Implements hook_node_prepare_form().
  */
-function datetime_node_prepare_form(NodeInterface $node, $operation, array &$form_state) {
+function datetime_node_prepare_form(NodeInterface $node, $operation, FormStateInterface $form_state) {
   // Prepare the 'Authored on' date to use datetime.
   $node->date = DrupalDateTime::createFromTimestamp($node->getCreatedTime());
 }
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
index c282db6..5bff36f 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Field\FormatterBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -162,7 +163,7 @@ function dateFormat($date) {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $time = new DrupalDateTime();
     $format_types = $this->dateStorage->loadMultiple();
     foreach ($format_types as $type => $type_info) {
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
index 75a59ec..4ed473b 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemList;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Represents a configurable entity datetime field.
@@ -25,7 +26,7 @@ class DateTimeFieldItemList extends FieldItemList {
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesForm(array &$form, array &$form_state) {
+  public function defaultValuesForm(array &$form, FormStateInterface $form_state) {
     if (empty($this->getFieldDefinition()->default_value_function)) {
       $default_value = $this->getFieldDefinition()->default_value;
 
@@ -48,12 +49,12 @@ public function defaultValuesForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesFormValidate(array $element, array &$form, array &$form_state) { }
+  public function defaultValuesFormValidate(array $element, array &$form, FormStateInterface $form_state) { }
 
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) {
+  public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['default_value_input']['default_date']) {
       return array($form_state['values']['default_value_input']);
     }
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
index 615ca1e..992af1e 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\datetime\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\Field\FieldItemBase;
 
@@ -83,7 +84,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element = array();
 
     $element['datetime_type'] = array(
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
index c9c3195..6d05a06 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
@@ -8,6 +8,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 
 /**
@@ -37,7 +38,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $date_order = $this->getSetting('date_order');
     $time_type = $this->getSetting('time_type');
     $increment = $this->getSetting('increment');
@@ -122,7 +123,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  function settingsForm(array $form, array &$form_state) {
+  function settingsForm(array $form, FormStateInterface $form_state) {
     $element = parent::settingsForm($form, $form_state);
 
     $element['date_order'] = array(
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
index 00426c0..a411eb4 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -60,7 +61,7 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     // We are nesting some sub-elements inside the parent, so we need a wrapper.
     // We also need to add another #title attribute at the top level for ease in
     // identifying this item in error messages. We do not want to display this
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index d6e20ff..c941c06 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -11,6 +11,7 @@
  * @see watchdog()
  */
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -37,9 +38,9 @@ function dblog_help($route_name, RouteMatchInterface $route_match) {
 }
 
 /**
- * Implements hook_menu_link_defaults_alter().
+ * Implements hook_menu_links_discovered_alter().
  */
-function dblog_menu_link_defaults_alter(&$links) {
+function dblog_menu_links_discovered_alter(&$links) {
   if (\Drupal::moduleHandler()->moduleExists('search')) {
     $links['dblog.search'] = array(
       'title' => 'Top search phrases',
@@ -112,6 +113,6 @@ function dblog_form_system_logging_settings_alter(&$form, $form_state) {
  *
  * @see dblog_form_system_logging_settings_alter()
  */
-function dblog_logging_settings_submit($form, &$form_state) {
+function dblog_logging_settings_submit($form, FormStateInterface $form_state) {
   \Drupal::config('dblog.settings')->set('row_limit', $form_state['values']['dblog_row_limit'])->save();
 }
diff --git a/core/modules/dblog/src/Form/DblogClearLogConfirmForm.php b/core/modules/dblog/src/Form/DblogClearLogConfirmForm.php
index d20181b..d2b6a89 100644
--- a/core/modules/dblog/src/Form/DblogClearLogConfirmForm.php
+++ b/core/modules/dblog/src/Form/DblogClearLogConfirmForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\dblog\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Form\ConfirmFormBase;
@@ -67,7 +68,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $_SESSION['dblog_overview_filter'] = array();
     $this->connection->delete('watchdog')->execute();
     drupal_set_message($this->t('Database log cleared.'));
diff --git a/core/modules/dblog/src/Form/DblogClearLogForm.php b/core/modules/dblog/src/Form/DblogClearLogForm.php
index 133ab43..f3781d4 100644
--- a/core/modules/dblog/src/Form/DblogClearLogForm.php
+++ b/core/modules/dblog/src/Form/DblogClearLogForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -53,7 +54,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['dblog_clear'] = array(
       '#type' => 'details',
       '#title' => $this->t('Clear log messages'),
@@ -69,7 +70,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = new Url('dblog.confirm');
   }
 
diff --git a/core/modules/dblog/src/Form/DblogFilterForm.php b/core/modules/dblog/src/Form/DblogFilterForm.php
index 2422472..aae5784 100644
--- a/core/modules/dblog/src/Form/DblogFilterForm.php
+++ b/core/modules/dblog/src/Form/DblogFilterForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\dblog\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides the database logging filter form.
@@ -24,7 +25,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $filters = dblog_filters();
 
     $form['filters'] = array(
@@ -67,7 +68,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if (empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
       $this->setFormError('type', $form_state, $this->t('You must select something to filter by.'));
     }
@@ -76,7 +77,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $filters = dblog_filters();
     foreach ($filters as $name => $filter) {
       if (isset($form_state['values'][$name])) {
@@ -88,7 +89,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Resets the filter form.
    */
-  public function resetForm(array &$form, array &$form_state) {
+  public function resetForm(array &$form, FormStateInterface $form_state) {
     $_SESSION['dblog_overview_filter'] = array();
   }
 
diff --git a/core/modules/dblog/src/Plugin/views/field/DblogMessage.php b/core/modules/dblog/src/Plugin/views/field/DblogMessage.php
index e6595d2..6c94184 100644
--- a/core/modules/dblog/src/Plugin/views/field/DblogMessage.php
+++ b/core/modules/dblog/src/Plugin/views/field/DblogMessage.php
@@ -8,6 +8,7 @@
 namespace Drupal\dblog\Plugin\views\field;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
@@ -46,7 +47,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['replace_variables'] = array(
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index 5aa7929..4ee1ddd 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\editor\Entity\Editor;
@@ -40,12 +41,12 @@ function editor_help($route_name, RouteMatchInterface $route_match) {
 }
 
 /**
- * Implements hook_menu_link_defaults_alter().
+ * Implements hook_menu_links_discovered_alter().
  *
  * Rewrites the menu entries for filter module that relate to the configuration
  * of text editors.
  */
-function editor_menu_link_defaults_alter(array &$links) {
+function editor_menu_links_discovered_alter(array &$links) {
   $links['filter.admin_overview']['title'] = 'Text formats and editors';
   $links['filter.admin_overview']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
 }
@@ -91,7 +92,7 @@ function editor_form_filter_admin_overview_alter(&$form, $form_state) {
 /**
  * Implements hook_form_BASE_FORM_ID_alter() for 'filter_format_form'.
  */
-function editor_form_filter_format_form_alter(&$form, &$form_state) {
+function editor_form_filter_format_form_alter(&$form, FormStateInterface $form_state) {
   if (!isset($form_state['editor'])) {
     $format_id = $form_state['controller']->getEntity()->id();
     $form_state['editor'] = editor_load($format_id);
@@ -168,7 +169,7 @@ function editor_form_filter_format_form_alter(&$form, &$form_state) {
 /**
  * Button submit handler for filter_format_form()'s 'editor_configure' button.
  */
-function editor_form_filter_admin_format_editor_configure($form, &$form_state) {
+function editor_form_filter_admin_format_editor_configure($form, FormStateInterface $form_state) {
   $editor = $form_state['editor'];
   if (isset($form_state['values']['editor']['editor'])) {
     if ($form_state['values']['editor']['editor'] === '') {
@@ -188,14 +189,14 @@ function editor_form_filter_admin_format_editor_configure($form, &$form_state) {
 /**
  * AJAX callback handler for filter_format_form().
  */
-function editor_form_filter_admin_form_ajax($form, &$form_state) {
+function editor_form_filter_admin_form_ajax($form, FormStateInterface $form_state) {
   return $form['editor']['settings'];
 }
 
 /**
  * Additional validate handler for filter_format_form().
  */
-function editor_form_filter_admin_format_validate($form, &$form_state) {
+function editor_form_filter_admin_format_validate($form, FormStateInterface $form_state) {
   // This validate handler is not applicable when using the 'Configure' button.
   if ($form_state['triggering_element']['#name'] === 'editor_configure') {
     return;
@@ -213,7 +214,7 @@ function editor_form_filter_admin_format_validate($form, &$form_state) {
 /**
  * Additional submit handler for filter_format_form().
  */
-function editor_form_filter_admin_format_submit($form, &$form_state) {
+function editor_form_filter_admin_format_submit($form, FormStateInterface $form_state) {
   // Delete the existing editor if disabling or switching between editors.
   $format_id = $form_state['controller']->getEntity()->id();
   $original_editor = editor_load($format_id);
diff --git a/core/modules/editor/src/Form/EditorImageDialog.php b/core/modules/editor/src/Form/EditorImageDialog.php
index 82524b6..f8c45e9 100644
--- a/core/modules/editor/src/Form/EditorImageDialog.php
+++ b/core/modules/editor/src/Form/EditorImageDialog.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Bytes;
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\filter\Entity\FilterFormat;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\HtmlCommand;
@@ -34,7 +35,7 @@ public function getFormId() {
    * @param \Drupal\filter\Entity\FilterFormat $filter_format
    *   The filter format for which this dialog corresponds.
    */
-  public function buildForm(array $form, array &$form_state, FilterFormat $filter_format = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL) {
     // The default values are set directly from \Drupal::request()->request,
     // provided by the editor plugin opening the dialog.
     if (!isset($form_state['image_element'])) {
@@ -184,7 +185,7 @@ public function buildForm(array $form, array &$form_state, FilterFormat $filter_
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $response = new AjaxResponse();
 
     // Convert any uploaded files from the FID values to data-editor-file-uuid
diff --git a/core/modules/editor/src/Form/EditorLinkDialog.php b/core/modules/editor/src/Form/EditorLinkDialog.php
index b0beb5b..8f31c3c 100644
--- a/core/modules/editor/src/Form/EditorLinkDialog.php
+++ b/core/modules/editor/src/Form/EditorLinkDialog.php
@@ -8,6 +8,7 @@
 namespace Drupal\editor\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\filter\Entity\FilterFormat;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\HtmlCommand;
@@ -32,7 +33,7 @@ public function getFormId() {
    * @param \Drupal\filter\Entity\FilterFormat $filter_format
    *   The filter format for which this dialog corresponds.
    */
-  public function buildForm(array $form, array &$form_state, FilterFormat $filter_format = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL) {
     // The default values are set directly from \Drupal::request()->request,
     // provided by the editor plugin opening the dialog.
     $input = isset($form_state['input']['editor_object']) ? $form_state['input']['editor_object'] : array();
@@ -78,7 +79,7 @@ public function buildForm(array $form, array &$form_state, FilterFormat $filter_
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $response = new AjaxResponse();
 
     if (form_get_errors($form_state)) {
diff --git a/core/modules/editor/src/Plugin/EditorBase.php b/core/modules/editor/src/Plugin/EditorBase.php
index 32e4408..4cb1fe2 100644
--- a/core/modules/editor/src/Plugin/EditorBase.php
+++ b/core/modules/editor/src/Plugin/EditorBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\editor\Plugin;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\editor\Entity\Editor;
 use Drupal\editor\Plugin\EditorPluginInterface;
@@ -54,20 +55,20 @@ public function getDefaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state, Editor $editor) {
+  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
     return $form;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function settingsFormValidate(array $form, array &$form_state) {
+  public function settingsFormValidate(array $form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function settingsFormSubmit(array $form, array &$form_state) {
+  public function settingsFormSubmit(array $form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/editor/src/Plugin/EditorPluginInterface.php b/core/modules/editor/src/Plugin/EditorPluginInterface.php
index c6b6c54..10ad314 100644
--- a/core/modules/editor/src/Plugin/EditorPluginInterface.php
+++ b/core/modules/editor/src/Plugin/EditorPluginInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\editor\Plugin;
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\Entity\Editor;
 
 /**
@@ -37,7 +38,7 @@ public function getDefaultSettings();
    *
    * @param array $form
    *   An empty form array to be populated with a configuration form, if any.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The state of the entire filter administration form.
    * @param \Drupal\editor\Entity\Editor $editor
    *   A configured text editor object.
@@ -45,7 +46,7 @@ public function getDefaultSettings();
    * @return array
    *   A render array for the settings form.
    */
-  public function settingsForm(array $form, array &$form_state, Editor $editor);
+  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor);
 
   /**
    * Validates the settings form for an editor.
@@ -56,10 +57,10 @@ public function settingsForm(array $form, array &$form_state, Editor $editor);
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function settingsFormValidate(array $form, array &$form_state);
+  public function settingsFormValidate(array $form, FormStateInterface $form_state);
 
   /**
    * Modifies any values in the form state to prepare them for saving.
@@ -69,10 +70,10 @@ public function settingsFormValidate(array $form, array &$form_state);
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function settingsFormSubmit(array $form, array &$form_state);
+  public function settingsFormSubmit(array $form, FormStateInterface $form_state);
 
   /**
    * Returns JavaScript settings to be attached.
diff --git a/core/modules/editor/tests/modules/src/Plugin/Editor/UnicornEditor.php b/core/modules/editor/tests/modules/src/Plugin/Editor/UnicornEditor.php
index 5015759..6937fb2 100644
--- a/core/modules/editor/tests/modules/src/Plugin/Editor/UnicornEditor.php
+++ b/core/modules/editor/tests/modules/src/Plugin/Editor/UnicornEditor.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\editor_test\Plugin\Editor;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\Plugin\EditorBase;
 use Drupal\editor\Entity\Editor as EditorEntity;
 
@@ -33,7 +34,7 @@ function getDefaultSettings() {
   /**
    * {@inheritdoc}
    */
-  function settingsForm(array $form, array &$form_state, EditorEntity $editor) {
+  function settingsForm(array $form, FormStateInterface $form_state, EditorEntity $editor) {
     $form['foo'] = array(
       '#title' => t('Foo'),
       '#type' => 'textfield',
diff --git a/core/modules/entity/src/Controller/EntityDisplayModeController.php b/core/modules/entity/src/Controller/EntityDisplayModeController.php
index f0db942..af31044 100644
--- a/core/modules/entity/src/Controller/EntityDisplayModeController.php
+++ b/core/modules/entity/src/Controller/EntityDisplayModeController.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Url;
 
 /**
  * Provides methods for entity display mode routes.
@@ -26,7 +27,7 @@ public function viewModeTypeSelection() {
       if ($entity_type->isFieldable() && $entity_type->hasViewBuilderClass()) {
         $entity_types[$entity_type_id] = array(
           'title' => $entity_type->getLabel(),
-          'link_path' => 'admin/structure/display-modes/view/add/' . $entity_type_id,
+          'url' => new Url('entity.view_mode_add_type', array('entity_type_id' => $entity_type_id)),
           'localized_options' => array(),
         );
       }
@@ -49,7 +50,7 @@ public function formModeTypeSelection() {
       if ($entity_type->isFieldable() && $entity_type->hasFormClasses()) {
         $entity_types[$entity_type_id] = array(
           'title' => $entity_type->getLabel(),
-          'link_path' => 'admin/structure/display-modes/form/add/' . $entity_type_id,
+          'url' => new Url('entity.form_mode_add_type', array('entity_type_id' => $entity_type_id)),
           'localized_options' => array(),
         );
       }
diff --git a/core/modules/entity/src/Entity/EntityFormDisplay.php b/core/modules/entity/src/Entity/EntityFormDisplay.php
index 8365032..6457e23 100644
--- a/core/modules/entity/src/Entity/EntityFormDisplay.php
+++ b/core/modules/entity/src/Entity/EntityFormDisplay.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity\EntityDisplayBase;
 
 /**
@@ -148,7 +149,7 @@ public function getRenderer($field_name) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(ContentEntityInterface $entity, array &$form, array &$form_state) {
+  public function buildForm(ContentEntityInterface $entity, array &$form, FormStateInterface $form_state) {
     // Set #parents to 'top-level' by default.
     $form += array('#parents' => array());
 
@@ -197,7 +198,7 @@ public function processForm($element, $form_state, $form) {
   /**
    * {@inheritdoc}
    */
-  public function extractFormValues(ContentEntityInterface $entity, array &$form, array &$form_state) {
+  public function extractFormValues(ContentEntityInterface $entity, array &$form, FormStateInterface $form_state) {
     $extracted = array();
     foreach ($entity as $name => $items) {
       if ($widget = $this->getRenderer($name)) {
@@ -211,7 +212,7 @@ public function extractFormValues(ContentEntityInterface $entity, array &$form,
   /**
    * {@inheritdoc}
    */
-  public function validateFormValues(ContentEntityInterface $entity, array &$form, array &$form_state) {
+  public function validateFormValues(ContentEntityInterface $entity, array &$form, FormStateInterface $form_state) {
     foreach ($entity as $field_name => $items) {
       // Only validate the fields that actually appear in the form, and let the
       // widget assign the violations to the right form elements.
diff --git a/core/modules/entity/src/Form/EntityDisplayModeAddForm.php b/core/modules/entity/src/Form/EntityDisplayModeAddForm.php
index 49be44f..296fde2 100644
--- a/core/modules/entity/src/Form/EntityDisplayModeAddForm.php
+++ b/core/modules/entity/src/Form/EntityDisplayModeAddForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\entity\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -24,7 +25,7 @@ class EntityDisplayModeAddForm extends EntityDisplayModeFormBase {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL) {
     $this->targetEntityTypeId = $entity_type_id;
     $form = parent::buildForm($form, $form_state);
     // Change replace_pattern to avoid undesired dots.
@@ -37,7 +38,7 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     form_set_value($form['id'], $this->targetEntityTypeId . '.' . $form_state['values']['id'], $form_state);
diff --git a/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php b/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php
index 091d5fe..b76d56b 100644
--- a/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php
+++ b/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -48,7 +49,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     $entity_type = $this->entity->getEntityType();
diff --git a/core/modules/entity/src/Form/EntityDisplayModeFormBase.php b/core/modules/entity/src/Form/EntityDisplayModeFormBase.php
index e848413..52e3388 100644
--- a/core/modules/entity/src/Form/EntityDisplayModeFormBase.php
+++ b/core/modules/entity/src/Form/EntityDisplayModeFormBase.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -64,7 +65,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  protected function init(array &$form_state) {
+  protected function init(FormStateInterface $form_state) {
     parent::init($form_state);
     $this->entityType = $this->entityManager->getDefinition($this->entity->getEntityTypeId());
   }
@@ -72,7 +73,7 @@ protected function init(array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['label'] = array(
       '#type' => 'textfield',
       '#title' => t('Label'),
@@ -102,13 +103,11 @@ public function form(array $form, array &$form_state) {
    *   The entity ID.
    * @param array $element
    *   The form element.
-   * @param array $form_state
-   *   The form state.
    *
    * @return bool
    *   TRUE if the display mode exists, FALSE otherwise.
    */
-  public function exists($entity_id, array $element, array $form_state) {
+  public function exists($entity_id, array $element) {
     // Do not allow to add internal 'default' view mode.
     if ($entity_id == 'default') {
       return TRUE;
@@ -122,7 +121,7 @@ public function exists($entity_id, array $element, array $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     drupal_set_message(t('Saved the %label @entity-type.', array('%label' => $this->entity->label(), '@entity-type' => $this->entityType->getLowercaseLabel())));
     $this->entity->save();
     \Drupal::entityManager()->clearCachedFieldDefinitions();
diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module
index 7fcc560..d1babc8 100644
--- a/core/modules/entity_reference/entity_reference.module
+++ b/core/modules/entity_reference/entity_reference.module
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Database\Query\AlterableInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\field\Entity\FieldStorageConfig;
@@ -147,7 +148,7 @@ function _entity_reference_form_process_merge_parent($element) {
 /**
  * Form element validation handler; Filters the #value property of an element.
  */
-function _entity_reference_element_validate_filter(&$element, &$form_state) {
+function _entity_reference_element_validate_filter(&$element, FormStateInterface $form_state) {
   $element['#value'] = array_filter($element['#value']);
   form_set_value($element, $element['#value'], $form_state);
 }
@@ -167,7 +168,7 @@ function entity_reference_settings_ajax($form, $form_state) {
  *
  * @see entity_reference_field_instance_settings_form()
  */
-function entity_reference_settings_ajax_submit($form, &$form_state) {
+function entity_reference_settings_ajax_submit($form, FormStateInterface $form_state) {
   $form_state['rebuild'] = TRUE;
 }
 
diff --git a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
index 269ad8c..032a365 100644
--- a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
+++ b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\OptGroup;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\AllowedValuesInterface;
@@ -159,7 +160,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element['target_type'] = array(
       '#type' => 'select',
       '#title' => t('Type of item to reference'),
@@ -176,7 +177,7 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $instance = $form_state['instance'];
 
     // Get all selection plugins for this entity type.
@@ -247,10 +248,10 @@ public function instanceSettingsForm(array $form, array &$form_state) {
    *
    * @param array $form
    *   The form where the settings form is being included in.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state of the (entire) configuration form.
    */
-  public static function instanceSettingsFormValidate(array $form, array &$form_state) {
+  public static function instanceSettingsFormValidate(array $form, FormStateInterface $form_state) {
     if (isset($form_state['values']['instance'])) {
       unset($form_state['values']['instance']['settings']['handler_submit']);
       $form_state['instance']->settings = $form_state['values']['instance']['settings'];
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
index 15f1df1..448343e 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity_reference\Plugin\Field\FieldFormatter;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity_reference\RecursiveRenderingException;
 
 /**
@@ -37,7 +38,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements['view_mode'] = array(
       '#type' => 'select',
       '#options' => \Drupal::entityManager()->getViewModeOptions($this->getFieldSetting('target_type')),
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
index 54a1ae7..154759f 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'entity reference label' formatter.
@@ -36,7 +37,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements['link'] = array(
       '#title' => t('Link label to the referenced entity'),
       '#type' => 'checkbox',
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldType/ConfigurableEntityReferenceFieldItemList.php b/core/modules/entity_reference/src/Plugin/Field/FieldType/ConfigurableEntityReferenceFieldItemList.php
index 3d4bec3..25d8546 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldType/ConfigurableEntityReferenceFieldItemList.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldType/ConfigurableEntityReferenceFieldItemList.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Field\EntityReferenceFieldItemList;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Represents a configurable entity_reference entity field.
@@ -73,7 +74,7 @@ public static function processDefaultValue($default_value, ContentEntityInterfac
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) {
+  public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) {
     $default_value = parent::defaultValuesFormSubmit($element, $form, $form_state);
 
     // Convert numeric IDs to UUIDs to ensure config deployability.
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
index f930de2..b289a06 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteTagsWidget.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\Tags;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'entity_reference autocomplete-tags' widget.
@@ -39,7 +40,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function elementValidate($element, &$form_state, $form) {
+  public function elementValidate($element, FormStateInterface $form_state, $form) {
     $value = array();
     // If a value was entered into the autocomplete.
     $handler = \Drupal::service('plugin.manager.entity_reference.selection')->getSelectionHandler($this->fieldDefinition);
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php
index 234eb7a..3633b5d 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity_reference\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'entity_reference autocomplete' widget.
@@ -57,7 +58,7 @@ protected function getEntityIds(FieldItemListInterface $items, $delta) {
   /**
    * {@inheritdoc}
    */
-  public function elementValidate($element, &$form_state, $form) {
+  public function elementValidate($element, FormStateInterface $form_state, $form) {
     $auto_create = $this->getSelectionHandlerSetting('auto_create');
 
     // If a value was entered into the autocomplete.
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
index 2ed1dfe..975ec4f 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\EntityOwnerInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
@@ -21,7 +22,7 @@
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['match_operator'] = array(
       '#type' => 'radios',
       '#title' => t('Autocomplete matching'),
@@ -70,7 +71,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $entity = $items->getEntity();
 
     // Prepare the autocomplete route parameters.
@@ -103,14 +104,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
     return $element['target_id'];
   }
 
   /**
    * Validates an element.
    */
-  public function elementValidate($element, &$form_state, $form) { }
+  public function elementValidate($element, FormStateInterface $form_state, $form) { }
 
   /**
    * Gets the entity labels.
diff --git a/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionBroken.php b/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionBroken.php
index eab272e..37a5264 100644
--- a/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionBroken.php
+++ b/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionBroken.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * A null implementation of SelectionInterface.
@@ -49,7 +50,7 @@ public function validateReferenceableEntities(array $ids) {
   /**
    * {@inheritdoc}
    */
-  public function validateAutocompleteInput($input, &$element, &$form_state, $form, $strict = TRUE) { }
+  public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE) { }
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionInterface.php b/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionInterface.php
index 28fc2c5..eb3b8ae 100644
--- a/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionInterface.php
+++ b/core/modules/entity_reference/src/Plugin/Type/Selection/SelectionInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Interface definition for Entity Reference Selection plugins.
@@ -54,6 +55,10 @@ public function validateReferenceableEntities(array $ids);
    *   Single string from autocomplete widget.
    * @param array $element
    *   The form element to set a form error.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   * @param array $form
+   *   The form.
    * @param boolean $strict
    *   Whether to trigger a form error if an element from $input (eg. an entity)
    *   is not found. Defaults to TRUE.
@@ -63,7 +68,7 @@ public function validateReferenceableEntities(array $ids);
    *
    * @see \Drupal\entity_reference\Plugin\Field\FieldWidget::elementValidate()
    */
-  public function validateAutocompleteInput($input, &$element, &$form_state, $form, $strict = TRUE);
+  public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE);
 
   /**
    * Allows the selection to alter the SelectQuery generated by EntityFieldQuery.
diff --git a/core/modules/entity_reference/src/Plugin/entity_reference/selection/SelectionBase.php b/core/modules/entity_reference/src/Plugin/entity_reference/selection/SelectionBase.php
index 11ee6cd..fbb6537 100644
--- a/core/modules/entity_reference/src/Plugin/entity_reference/selection/SelectionBase.php
+++ b/core/modules/entity_reference/src/Plugin/entity_reference/selection/SelectionBase.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface;
 
 /**
@@ -229,7 +230,7 @@ public function validateReferenceableEntities(array $ids) {
   /**
    * {@inheritdoc}
    */
-  public function validateAutocompleteInput($input, &$element, &$form_state, $form, $strict = TRUE) {
+  public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE) {
     $bundled_entities = $this->getReferenceableEntities($input, '=', 6);
     $entities = array();
     foreach ($bundled_entities as $entities_list) {
diff --git a/core/modules/entity_reference/src/Plugin/views/row/EntityReference.php b/core/modules/entity_reference/src/Plugin/views/row/EntityReference.php
index b975b0a..8434e97 100644
--- a/core/modules/entity_reference/src/Plugin/views/row/EntityReference.php
+++ b/core/modules/entity_reference/src/Plugin/views/row/EntityReference.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\entity_reference\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\Fields;
 
 /**
@@ -38,7 +39,7 @@ protected function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\row\Fields::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Expand the description of the 'Inline field' checkboxes.
diff --git a/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php b/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php
index 37a446b..d0b3bbe 100644
--- a/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php
+++ b/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity_reference\Plugin\views\style;
 
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\style\StylePluginBase;
 
 /**
@@ -54,7 +55,7 @@ protected function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $options = $this->displayHandler->getFieldLabels(TRUE);
diff --git a/core/modules/entity_reference/tests/modules/entity_reference_test/config/install/views.view.test_entity_reference.yml b/core/modules/entity_reference/tests/modules/entity_reference_test/config/install/views.view.test_entity_reference.yml
index 2bb54bd..46c20ac 100644
--- a/core/modules/entity_reference/tests/modules/entity_reference_test/config/install/views.view.test_entity_reference.yml
+++ b/core/modules/entity_reference/tests/modules/entity_reference_test/config/install/views.view.test_entity_reference.yml
@@ -9,6 +9,7 @@ display:
     id: entity_reference_1
     display_title: EntityReference
     position: null
+    provider: entity_reference
     display_options:
       style:
         type: entity_reference
@@ -116,3 +117,6 @@ module: entity_reference_test
 id: test_entity_reference
 tag: ''
 langcode: en
+dependencies:
+  module:
+    - entity_reference
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 62a8c1c..543561e7 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -105,7 +105,7 @@ function hook_field_widget_info_alter(array &$info) {
  * @param $element
  *   The field widget form element as constructed by hook_field_widget_form().
  * @param $form_state
- *   An associative array containing the current state of the form.
+ *   The current state of the form.
  * @param $context
  *   An associative array containing the following key-value pairs:
  *   - form: The form structure to which widgets are being attached. This may be
@@ -120,7 +120,7 @@ function hook_field_widget_info_alter(array &$info) {
  * @see \Drupal\Core\Field\WidgetBase::formSingleElement()
  * @see hook_field_widget_WIDGET_TYPE_form_alter()
  */
-function hook_field_widget_form_alter(&$element, &$form_state, $context) {
+function hook_field_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
   // Add a css class to widget form elements for all fields of type mytype.
   $field_definition = $context['items']->getFieldDefinition();
   if ($field_definition->getType() == 'mytype') {
@@ -139,7 +139,7 @@ function hook_field_widget_form_alter(&$element, &$form_state, $context) {
  * @param $element
  *   The field widget form element as constructed by hook_field_widget_form().
  * @param $form_state
- *   An associative array containing the current state of the form.
+ *   The current state of the form.
  * @param $context
  *   An associative array. See hook_field_widget_form_alter() for the structure
  *   and content of the array.
@@ -147,7 +147,7 @@ function hook_field_widget_form_alter(&$element, &$form_state, $context) {
  * @see \Drupal\Core\Field\WidgetBase::formSingleElement()
  * @see hook_field_widget_form_alter()
  */
-function hook_field_widget_WIDGET_TYPE_form_alter(&$element, &$form_state, $context) {
+function hook_field_widget_WIDGET_TYPE_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
   // Code here will only act on widgets of type WIDGET_TYPE.  For example,
   // hook_field_widget_mymodule_autocomplete_form_alter() will only act on
   // widgets of type 'mymodule_autocomplete'.
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 444a92d..8bcb693 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -10,6 +10,7 @@
 use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Extension\Extension;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /*
@@ -344,7 +345,7 @@ function field_config_import_steps_alter(&$sync_steps, ConfigImporter $config_im
  *
  * @see \Drupal\field\ConfigImporterFieldPurger
  */
-function field_form_config_admin_import_form_alter(&$form, &$form_state) {
+function field_form_config_admin_import_form_alter(&$form, FormStateInterface $form_state) {
   // Only display the message when there is a storage comparer available and the
   // form is not submitted.
   if (isset($form_state['storage_comparer']) && empty($form_state['input'])) {
diff --git a/core/modules/field/src/Plugin/views/argument/FieldList.php b/core/modules/field/src/Plugin/views/argument/FieldList.php
index 5bfd935..08c7756 100644
--- a/core/modules/field/src/Plugin/views/argument/FieldList.php
+++ b/core/modules/field/src/Plugin/views/argument/FieldList.php
@@ -8,6 +8,7 @@
 namespace Drupal\field\Plugin\views\argument;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\argument\Numeric;
@@ -47,7 +48,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['summary']['human'] = array(
diff --git a/core/modules/field/src/Plugin/views/argument/ListString.php b/core/modules/field/src/Plugin/views/argument/ListString.php
index 02d049a..eee75e2 100644
--- a/core/modules/field/src/Plugin/views/argument/ListString.php
+++ b/core/modules/field/src/Plugin/views/argument/ListString.php
@@ -8,6 +8,7 @@
 namespace Drupal\field\Plugin\views\argument;
 
 use Drupal\Component\Utility\String as UtilityString;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\argument\String;
@@ -48,7 +49,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['summary']['human'] = array(
diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php
index ad3543b..e4103f3 100644
--- a/core/modules/field/src/Plugin/views/field/Field.php
+++ b/core/modules/field/src/Plugin/views/field/Field.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\FormatterPluginManager;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Render\Element;
@@ -435,7 +436,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $field = $this->getFieldDefinition();
@@ -516,7 +517,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Provide options for multiple value fields.
    */
-  function multiple_options_form(&$form, &$form_state) {
+  function multiple_options_form(&$form, FormStateInterface $form_state) {
     $field = $this->getFieldDefinition();
 
     $form['multiple_field_settings'] = array(
@@ -639,7 +640,7 @@ function multiple_options_form(&$form, &$form_state) {
   /**
    * Extend the groupby form with group columns.
    */
-  public function buildGroupByForm(&$form, &$form_state) {
+  public function buildGroupByForm(&$form, FormStateInterface $form_state) {
     parent::buildGroupByForm($form, $form_state);
     // With "field API" fields, the column target of the grouping function
     // and any additional grouping columns must be specified.
@@ -672,7 +673,7 @@ public function buildGroupByForm(&$form, &$form_state) {
     );
   }
 
-  public function submitGroupByForm(&$form, &$form_state) {
+  public function submitGroupByForm(&$form, FormStateInterface $form_state) {
     parent::submitGroupByForm($form, $form_state);
     $item = &$form_state['handler']->options;
 
diff --git a/core/modules/field/src/Tests/FieldAttachOtherTest.php b/core/modules/field/src/Tests/FieldAttachOtherTest.php
index 7356bce..a74e4d2 100644
--- a/core/modules/field/src/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/src/Tests/FieldAttachOtherTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\field\Tests;
 
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
@@ -265,7 +266,7 @@ function testEntityFormDisplayBuildForm() {
     // Test generating widgets for all fields.
     $display = entity_get_form_display($entity_type, $this->instance->bundle, 'default');
     $form = array();
-    $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $form_state = new FormState();
     $display->buildForm($entity, $form, $form_state);
 
     $this->assertEqual($form[$this->field_name]['widget']['#title'], $this->instance->getLabel(), "First field's form title is {$this->instance->getLabel()}");
@@ -287,7 +288,7 @@ function testEntityFormDisplayBuildForm() {
       }
     }
     $form = array();
-    $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $form_state = new FormState();
     $display->buildForm($entity, $form, $form_state);
 
     $this->assertFalse(isset($form[$this->field_name]), 'The first field does not exist in the form');
@@ -310,7 +311,7 @@ function testEntityFormDisplayExtractFormValues() {
     // Build the form for all fields.
     $display = entity_get_form_display($entity_type, $this->instance->bundle, 'default');
     $form = array();
-    $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $form_state = new FormState();
     $display->buildForm($entity_init, $form, $form_state);
 
     // Simulate incoming values.
diff --git a/core/modules/field/src/Tests/FormTest.php b/core/modules/field/src/Tests/FormTest.php
index 2457aa7..262a96d 100644
--- a/core/modules/field/src/Tests/FormTest.php
+++ b/core/modules/field/src/Tests/FormTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormState;
 
 /**
  * Tests field form handling.
@@ -531,7 +532,7 @@ function testFieldFormAccess() {
 
     $display = entity_get_form_display($entity_type, $entity_type, 'default');
     $form = array();
-    $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $form_state = new FormState();
     $display->buildForm($entity, $form, $form_state);
 
     $this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.');
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index 13c846d..499c883 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -2,6 +2,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\field\FieldStorageConfigInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * @file
@@ -115,7 +116,7 @@ function field_test_entity_display_build_alter(&$output, $context) {
 /**
  * Implements hook_field_widget_form_alter().
  */
-function field_test_field_widget_form_alter(&$element, &$form_state, $context) {
+function field_test_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
   $field_definition = $context['items']->getFieldDefinition();
   switch ($field_definition->getName()) {
     case 'alter_test_text':
diff --git a/core/modules/field/tests/modules/field_test/src/Form/NestedEntityTestForm.php b/core/modules/field/tests/modules/field_test/src/Form/NestedEntityTestForm.php
index 89aa42c..ea5a30e 100644
--- a/core/modules/field/tests/modules/field_test/src/Form/NestedEntityTestForm.php
+++ b/core/modules/field/tests/modules/field_test/src/Form/NestedEntityTestForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity\Entity\EntityFormDisplay;
 
 /**
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc]
    */
-  public function buildForm(array $form, array &$form_state, EntityInterface $entity_1 = NULL, EntityInterface $entity_2 = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity_1 = NULL, EntityInterface $entity_2 = NULL) {
     // First entity.
     $form_state['entity_1'] = $entity_1;
     $form_state['form_display_1'] = EntityFormDisplay::collectRenderDisplay($entity_1, 'default');
@@ -57,7 +58,7 @@ public function buildForm(array $form, array &$form_state, EntityInterface $enti
   /**
    * {@inheritdoc]
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $entity_1 = $form_state['entity_1'];
     /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display_1 */
     $form_display_1 = $form_state['form_display_1'];
@@ -74,7 +75,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc]
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     /** @var \Drupal\Core\Entity\EntityInterface $entity_1 */
     $entity_1 = $form_state['entity_1'];
     $entity_1->save();
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldDefaultFormatter.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldDefaultFormatter.php
index 3e61ca1..d195a31 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldDefaultFormatter.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldDefaultFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'field_test_default' formatter.
@@ -37,7 +38,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['test_formatter_setting'] = array(
       '#title' => t('Setting'),
       '#type' => 'textfield',
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldEmptySettingFormatter.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldEmptySettingFormatter.php
index 7cd25fb..84938ec 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldEmptySettingFormatter.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldEmptySettingFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'field_empty_setting' formatter.
@@ -36,7 +37,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['field_empty_setting'] = array(
       '#title' => t('Setting'),
       '#type' => 'textfield',
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldMultipleFormatter.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldMultipleFormatter.php
index 1aeb570..a310ad3 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldMultipleFormatter.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldMultipleFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'field_test_multiple' formatter.
@@ -37,7 +38,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['test_formatter_setting_multiple'] = array(
       '#title' => t('Setting'),
       '#type' => 'textfield',
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldPrepareViewFormatter.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldPrepareViewFormatter.php
index beb17e9..211c1cd 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldPrepareViewFormatter.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldFormatter/TestFieldPrepareViewFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'field_test_with_prepare_view' formatter.
@@ -37,7 +38,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['test_formatter_setting_additional'] = array(
       '#title' => t('Setting'),
       '#type' => 'textfield',
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
index 45302e3..5234964 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\field_test\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\Field\FieldItemBase;
 
@@ -76,7 +77,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $form['test_field_storage_setting'] = array(
       '#type' => 'textfield',
       '#title' => t('Field test field storage setting'),
@@ -91,7 +92,7 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $form['test_instance_setting'] = array(
       '#type' => 'textfield',
       '#title' => t('Field test field instance setting'),
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php
index 1fcc8bc..71b8afa 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -38,7 +39,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['test_widget_setting'] = array(
       '#type' => 'textfield',
       '#title' => t('Field test field widget setting'),
@@ -61,7 +62,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element += array(
       '#type' => 'textfield',
       '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : '',
@@ -72,7 +73,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     return $element['value'];
   }
 
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
index ac4609c..5ad37f4 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -40,7 +41,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['test_widget_setting_multiple'] = array(
       '#type' => 'textfield',
       '#title' => t('Field test field widget setting'),
@@ -63,7 +64,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $values = array();
     foreach ($items as $item) {
       $values[] = $item->value;
@@ -79,14 +80,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     return $element;
   }
 
   /**
    * Element validation helper.
    */
-  public static function multipleValidate($element, &$form_state) {
+  public static function multipleValidate($element, FormStateInterface $form_state) {
     $values = array_map('trim', explode(',', $element['#value']));
     $items = array();
     foreach ($values as $value) {
diff --git a/core/modules/field_ui/field_ui.api.php b/core/modules/field_ui/field_ui.api.php
index 070f020..b67d89b 100644
--- a/core/modules/field_ui/field_ui.api.php
+++ b/core/modules/field_ui/field_ui.api.php
@@ -21,7 +21,7 @@
  *   The entity view mode.
  * @param array $form
  *   The (entire) configuration form array.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The form state.
  *
  * @return array
@@ -54,7 +54,7 @@ function hook_field_formatter_third_party_settings_form(\Drupal\Core\Field\Forma
  *   The entity form mode.
  * @param array $form
  *   The (entire) configuration form array.
- * @param array $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The form state.
  *
  * @return array
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 4d475b4..336b587 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\entity\EntityViewModeInterface;
@@ -198,7 +199,7 @@ function field_ui_entity_operation(EntityInterface $entity) {
  *
  * @see field_ui_form_node_type_form_alter()
  */
-function field_ui_form_node_type_form_submit($form, &$form_state) {
+function field_ui_form_node_type_form_submit($form, FormStateInterface $form_state) {
   if ($form_state['triggering_element']['#parents'][0] === 'save_continue' && $route_info = FieldUI::getOverviewRouteInfo('node', $form_state['values']['type'])) {
     $form_state['redirect_route'] = $route_info;
   }
diff --git a/core/modules/field_ui/src/DisplayOverview.php b/core/modules/field_ui/src/DisplayOverview.php
index 3c55ec0..6d5a677 100644
--- a/core/modules/field_ui/src/DisplayOverview.php
+++ b/core/modules/field_ui/src/DisplayOverview.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Field\FieldTypePluginManager;
 use Drupal\Core\Field\FormatterInterface;
 use Drupal\Core\Field\PluginSettingsInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -77,7 +78,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL, $bundle = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
     if ($this->getRequest()->attributes->has('view_mode_name')) {
       $this->mode = $this->getRequest()->attributes->get('view_mode_name');
     }
@@ -88,7 +89,7 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
   /**
    * {@inheritdoc}
    */
-  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
+  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, FormStateInterface $form_state) {
     $field_row = parent::buildFieldRow($field_definition, $entity_display, $form, $form_state);
 
     $field_name = $field_definition->getName();
@@ -233,7 +234,7 @@ protected function getFieldLabelOptions() {
   /**
    * {@inheritdoc}
    */
-  protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state) {
+  protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
     $settings_form = array();
     // Invoke hook_field_formatter_third_party_settings_form(), keying resulting
     // subforms by module name.
diff --git a/core/modules/field_ui/src/DisplayOverviewBase.php b/core/modules/field_ui/src/DisplayOverviewBase.php
index f450313..e76b6b6 100644
--- a/core/modules/field_ui/src/DisplayOverviewBase.php
+++ b/core/modules/field_ui/src/DisplayOverviewBase.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Field\PluginSettingsInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -116,7 +117,7 @@ protected function getFieldDefinitions() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL, $bundle = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
     parent::buildForm($form, $form_state, $entity_type_id, $bundle);
 
     if (empty($this->mode)) {
@@ -127,10 +128,6 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
     $extra_fields = $this->getExtraFields();
     $entity_display = $this->getEntityDisplay($this->mode);
 
-    $form_state += array(
-      'plugin_settings_edit' => NULL,
-    );
-
     $form += array(
       '#entity_type' => $this->entity_type,
       '#bundle' => $this->bundle,
@@ -257,13 +254,13 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
    *   The entity display.
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   A table row array.
    */
-  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
+  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, FormStateInterface $form_state) {
     $field_name = $field_definition->getName();
     $display_options = $entity_display->getComponent($field_name);
     $label = $field_definition->getLabel();
@@ -509,7 +506,7 @@ protected function buildExtraFieldRow($field_id, $extra_field, EntityDisplayInte
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_values = $form_state['values'];
     $display = $this->getEntityDisplay($this->mode);
 
@@ -615,7 +612,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Form submission handler for multistep buttons.
    */
-  public function multistepSubmit($form, &$form_state) {
+  public function multistepSubmit($form, FormStateInterface $form_state) {
     $trigger = $form_state['triggering_element'];
     $op = $trigger['#op'];
 
@@ -659,7 +656,7 @@ public function multistepSubmit($form, &$form_state) {
   /**
    * Ajax handler for multistep buttons.
    */
-  public function multistepAjax($form, &$form_state) {
+  public function multistepAjax($form, FormStateInterface $form_state) {
     $trigger = $form_state['triggering_element'];
     $op = $trigger['#op'];
 
@@ -887,13 +884,13 @@ protected function saveDisplayStatuses($display_statuses) {
    *   The field definition.
    * @param array $form
    *   The (entire) configuration form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    *
    * @return array
    *   The widget or formatter third party settings form.
    */
-  abstract protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state);
+  abstract protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state);
 
   /**
    * Alters the widget or formatter settings summary.
diff --git a/core/modules/field_ui/src/FieldOverview.php b/core/modules/field_ui/src/FieldOverview.php
index c962dc9..ed2ef0b 100644
--- a/core/modules/field_ui/src/FieldOverview.php
+++ b/core/modules/field_ui/src/FieldOverview.php
@@ -12,6 +12,7 @@
 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\field_ui\OverviewBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -77,7 +78,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL, $bundle = NULL) {
+  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.
@@ -281,7 +282,7 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $this->validateAddNew($form, $form_state);
     $this->validateAddExisting($form, $form_state);
   }
@@ -291,12 +292,12 @@ public function validateForm(array &$form, array &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state 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, array &$form_state) {
+  protected function validateAddNew(array $form, FormStateInterface $form_state) {
     $field = $form_state['values']['fields']['_add_new_field'];
 
     // Validate if any information was provided in the 'add new field' row.
@@ -331,12 +332,12 @@ protected function validateAddNew(array $form, array &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state 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, array &$form_state) {
+  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 (isset($form_state['values']['fields']['_add_existing_field'])) {
@@ -361,7 +362,7 @@ protected function validateAddExisting(array $form, array &$form_state) {
   /**
    * Overrides \Drupal\field_ui\OverviewBase::submitForm().
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $error = FALSE;
     $form_values = $form_state['values']['fields'];
     $destinations = array();
diff --git a/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php b/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php
index 95f84f6..940d991 100644
--- a/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php
+++ b/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\field_ui\FieldUI;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -67,7 +68,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $field_storage = $this->entity->getFieldStorageDefinition();
     $bundles = entity_get_bundles();
     $bundle_label = $bundles[$this->entity->entity_type][$this->entity->bundle]['label'];
diff --git a/core/modules/field_ui/src/Form/FieldInstanceEditForm.php b/core/modules/field_ui/src/Form/FieldInstanceEditForm.php
index 12f881d..b03fd16 100644
--- a/core/modules/field_ui/src/Form/FieldInstanceEditForm.php
+++ b/core/modules/field_ui/src/Form/FieldInstanceEditForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\field\FieldInstanceConfigInterface;
 use Drupal\field_ui\FieldUI;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -62,7 +63,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, FieldInstanceConfigInterface $field_instance_config = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, FieldInstanceConfigInterface $field_instance_config = NULL) {
     $this->instance = $form_state['instance'] = $field_instance_config;
 
     $bundle = $this->instance->bundle;
@@ -164,7 +165,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceConfigIn
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if (isset($form['instance']['default_value'])) {
       $items = $form['#entity']->get($this->instance->getName());
       $items->defaultValuesFormValidate($form['instance']['default_value'], $form, $form_state);
@@ -174,7 +175,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Handle the default value.
     $default_value = array();
     if (isset($form['instance']['default_value'])) {
@@ -209,7 +210,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Redirects to the field instance deletion form.
    */
-  public function delete(array &$form, array &$form_state) {
+  public function delete(array &$form, FormStateInterface $form_state) {
     $destination = array();
     $request = $this->getRequest();
     if ($request->query->has('destination')) {
diff --git a/core/modules/field_ui/src/Form/FieldStorageEditForm.php b/core/modules/field_ui/src/Form/FieldStorageEditForm.php
index 7fb5819..830396c 100644
--- a/core/modules/field_ui/src/Form/FieldStorageEditForm.php
+++ b/core/modules/field_ui/src/Form/FieldStorageEditForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\TypedDataManager;
 use Drupal\field\FieldInstanceConfigInterface;
 use Drupal\field_ui\FieldUI;
@@ -74,7 +75,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, FieldInstanceConfigInterface $field_instance_config = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, FieldInstanceConfigInterface $field_instance_config = NULL) {
     $this->instance = $form_state['instance'] = $field_instance_config;
     $form['#title'] = $this->instance->label();
 
@@ -159,7 +160,7 @@ public function buildForm(array $form, array &$form_state, FieldInstanceConfigIn
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Validate field cardinality.
     $cardinality = $form_state['values']['field']['cardinality'];
     $cardinality_number = $form_state['values']['field']['cardinality_number'];
@@ -171,7 +172,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_values = $form_state['values'];
     $field_values = $form_values['field'];
 
diff --git a/core/modules/field_ui/src/FormDisplayOverview.php b/core/modules/field_ui/src/FormDisplayOverview.php
index 3a2546b..4857a53 100644
--- a/core/modules/field_ui/src/FormDisplayOverview.php
+++ b/core/modules/field_ui/src/FormDisplayOverview.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManager;
 use Drupal\Core\Field\PluginSettingsInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -76,7 +77,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL, $bundle = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $bundle = NULL) {
     if ($this->getRequest()->attributes->has('form_mode_name')) {
       $this->mode = $this->getRequest()->attributes->get('form_mode_name');
     }
@@ -87,7 +88,7 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
   /**
    * {@inheritdoc}
    */
-  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, array &$form_state) {
+  protected function buildFieldRow(FieldDefinitionInterface $field_definition, EntityDisplayInterface $entity_display, array $form, FormStateInterface $form_state) {
     $field_row = parent::buildFieldRow($field_definition, $entity_display, $form, $form_state);
 
     $field_name = $field_definition->getName();
@@ -183,7 +184,7 @@ protected function getOverviewRoute($mode) {
   /**
    * {@inheritdoc}
    */
-  protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, array &$form_state) {
+  protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
     $settings_form = array();
     // Invoke hook_field_widget_third_party_settings_form(), keying resulting
     // subforms by module name.
diff --git a/core/modules/field_ui/src/OverviewBase.php b/core/modules/field_ui/src/OverviewBase.php
index 17104e0..7132eda 100644
--- a/core/modules/field_ui/src/OverviewBase.php
+++ b/core/modules/field_ui/src/OverviewBase.php
@@ -9,6 +9,7 @@
 
 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;
 
@@ -74,7 +75,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_type_id = NULL, $bundle = NULL) {
+  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();
     if (!isset($form_state['bundle'])) {
@@ -89,9 +90,9 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 824be6d..a48a7a7 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\file\Entity\File;
@@ -686,8 +687,8 @@ function file_cron() {
  * @param $form_field_name
  *   A string that is the associative array key of the upload form element in
  *   the form array.
- * @param array $form_state
- *   An associative array containing the current state of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  * @param $validators
  *   An optional, associative array of callback functions used to validate the
  *   file. See file_validate() for a full discussion of the array format.
@@ -1103,7 +1104,7 @@ function file_token_info() {
  *
  * This function is assigned as a #process callback in file_element_info().
  */
-function file_managed_file_process($element, &$form_state, $form) {
+function file_managed_file_process($element, FormStateInterface $form_state, $form) {
   // Append the '-upload' to the #id so the field label's 'for' attribute
   // corresponds with the file element.
   $element['#id'] .= '-upload';
@@ -1250,7 +1251,7 @@ function file_managed_file_process($element, &$form_state, $form) {
  *
  * This function is assigned as a #value_callback in file_element_info().
  */
-function file_managed_file_value(&$element, $input, &$form_state) {
+function file_managed_file_value(&$element, $input, FormStateInterface $form_state) {
   // Find the current value of this field.
   $fids = !empty($input['fids']) ? explode(' ', $input['fids']) : array();
   foreach ($fids as $key => $fid) {
@@ -1326,7 +1327,7 @@ function file_managed_file_value(&$element, $input, &$form_state) {
  * This function is assigned as a #element_validate callback in
  * file_element_info().
  */
-function file_managed_file_validate(&$element, &$form_state) {
+function file_managed_file_validate(&$element, FormStateInterface $form_state) {
   // If referencing an existing file, only allow if there are existing
   // references. This prevents unmanaged files from being deleted if this
   // item were to be deleted.
@@ -1364,7 +1365,7 @@ function file_managed_file_validate(&$element, &$form_state) {
  *
  * @see file_managed_file_process()
  */
-function file_managed_file_submit($form, &$form_state) {
+function file_managed_file_submit($form, FormStateInterface $form_state) {
   // Determine whether it was the upload or the remove button that was clicked,
   // and set $element to the managed_file element that contains that button.
   $parents = $form_state['triggering_element']['#array_parents'];
@@ -1428,14 +1429,14 @@ function file_managed_file_submit($form, &$form_state) {
  *
  * @param $element
  *   The FAPI element whose values are being saved.
- * @param array $form_state
- *   An associative array containing the current state of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @return
  *   An array of file entities for each file that was saved, keyed by its file
  *   ID, or FALSE if no files were saved.
  */
-function file_managed_file_save_upload($element, array &$form_state) {
+function file_managed_file_save_upload($element, FormStateInterface $form_state) {
   $upload_name = implode('_', $element['#parents']);
   $file_upload = \Drupal::request()->files->get("files[$upload_name]", NULL, TRUE);
   if (empty($file_upload)) {
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileFieldItemList.php b/core/modules/file/src/Plugin/Field/FieldType/FileFieldItemList.php
index 43dbefa..f8ee03c 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileFieldItemList.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileFieldItemList.php
@@ -8,6 +8,7 @@
 namespace Drupal\file\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\EntityReferenceFieldItemList;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Represents a configurable entity file field.
@@ -17,7 +18,7 @@ class FileFieldItemList extends EntityReferenceFieldItemList {
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesForm(array &$form, array &$form_state) { }
+  public function defaultValuesForm(array &$form, FormStateInterface $form_state) { }
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index a56448a..9f80a6f 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Bytes;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 
 /**
@@ -106,7 +107,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element = array();
 
     $element['#attached']['library'][] = 'file/drupal.file';
@@ -148,7 +149,7 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
     $settings = $this->getSettings();
 
@@ -208,7 +209,7 @@ public function instanceSettingsForm(array $form, array &$form_state) {
    * This function is assigned as an #element_validate callback in
    * instanceSettingsForm().
    */
-  public static function validateDirectory($element, &$form_state) {
+  public static function validateDirectory($element, FormStateInterface $form_state) {
     // Strip slashes from the beginning and end of $element['file_directory'].
     $value = trim($element['#value'], '\\/');
     form_set_value($element, $value, $form_state);
@@ -224,7 +225,7 @@ public static function validateDirectory($element, &$form_state) {
    * Commas are allowed by the end-user, but ultimately the value will be stored
    * as a space-separated list for compatibility with file_validate_extensions().
    */
-  public static function validateExtensions($element, &$form_state) {
+  public static function validateExtensions($element, FormStateInterface $form_state) {
     if (!empty($element['#value'])) {
       $extensions = preg_replace('/([, ]+\.?)/', ' ', trim(strtolower($element['#value'])));
       $extensions = array_filter(explode(' ', $extensions));
@@ -247,7 +248,7 @@ public static function validateExtensions($element, &$form_state) {
    * This function is assigned as an #element_validate callback in
    * instanceSettingsForm().
    */
-  public static function validateMaxFilesize($element, &$form_state) {
+  public static function validateMaxFilesize($element, FormStateInterface $form_state) {
     if (!empty($element['#value']) && !is_numeric(Bytes::toInt($element['#value']))) {
       form_error($element, $form_state, t('The "!name" option must contain a valid value. You may either leave the text field empty or enter a string like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes).', array('!name' => t($element['title']))));
     }
diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
index 5f71e9a..9a03fe4 100644
--- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 
 /**
@@ -39,7 +40,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['progress_indicator'] = array(
       '#type' => 'radios',
       '#title' => t('Progress indicator'),
@@ -69,7 +70,7 @@ public function settingsSummary() {
    *
    * Special handling for draggable multiple widgets and 'add more' button.
    */
-  protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
+  protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
     $field_name = $this->fieldDefinition->getName();
     $parents = $form['#parents'];
 
@@ -186,7 +187,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $field_settings = $this->getFieldSettings();
 
     // The field settings include defaults for the field type. However, this
@@ -256,7 +257,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function massageFormValues(array $values, array $form, array &$form_state) {
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     // Since file upload widget now supports uploads of more than one file at a
     // time it always returns an array of fids. We have to translate this to a
     // single fid, as field expects single value.
@@ -306,7 +307,7 @@ public static function value($element, $input = FALSE, $form_state) {
    *
    * This validator is used only when cardinality not set to 1 or unlimited.
    */
-  public static function validateMultipleCount($element, &$form_state, $form) {
+  public static function validateMultipleCount($element, FormStateInterface $form_state, $form) {
     $parents = $element['#parents'];
     $values = NestedArray::getValue($form_state['values'], $parents);
 
@@ -341,7 +342,7 @@ public static function validateMultipleCount($element, &$form_state, $form) {
    *
    * This method is assigned as a #process callback in formElement() method.
    */
-  public static function process($element, &$form_state, $form) {
+  public static function process($element, FormStateInterface $form_state, $form) {
     $item = $element['#value'];
     $item['fids'] = $element['fids']['#value'];
 
@@ -419,7 +420,7 @@ public static function process($element, &$form_state, $form) {
    * This method on is assigned as a #process callback in formMultipleElements()
    * method.
    */
-  public static function processMultiple($element, &$form_state, $form) {
+  public static function processMultiple($element, FormStateInterface $form_state, $form) {
     $element_children = Element::children($element, TRUE);
     $count = count($element_children);
 
@@ -484,7 +485,7 @@ protected static function getDescriptionFromElement($element) {
    *
    * @see file_managed_file_submit()
    */
-  public static function submit($form, &$form_state) {
+  public static function submit($form, FormStateInterface $form_state) {
     // During the form rebuild, formElement() will create field item widget
     // elements using re-indexed deltas, so clear out $form_state['input'] to
     // avoid a mismatch between old and new deltas. The rebuilt elements will
diff --git a/core/modules/file/src/Plugin/views/field/Extension.php b/core/modules/file/src/Plugin/views/field/Extension.php
index 1272e2f..ba53c81 100644
--- a/core/modules/file/src/Plugin/views/field/Extension.php
+++ b/core/modules/file/src/Plugin/views/field/Extension.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\file\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 
@@ -31,7 +32,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['extension_detect_tar'] = array(
       '#type' => 'checkbox',
diff --git a/core/modules/file/src/Plugin/views/field/File.php b/core/modules/file/src/Plugin/views/field/File.php
index 0ce77e8..135ff7f 100644
--- a/core/modules/file/src/Plugin/views/field/File.php
+++ b/core/modules/file/src/Plugin/views/field/File.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\file\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -41,7 +42,7 @@ protected function defineOptions() {
   /**
    * Provide link to file option
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_file'] = array(
       '#title' => t('Link this field to download the file'),
       '#description' => t("Enable to override this field's links."),
diff --git a/core/modules/file/src/Plugin/views/field/FileMime.php b/core/modules/file/src/Plugin/views/field/FileMime.php
index fd1c355..5576e34 100644
--- a/core/modules/file/src/Plugin/views/field/FileMime.php
+++ b/core/modules/file/src/Plugin/views/field/FileMime.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\file\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -24,7 +25,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['filemime_image'] = array(
       '#title' => t('Display an icon representing the file type, instead of the MIME text (such as "image/jpeg")'),
       '#type' => 'checkbox',
diff --git a/core/modules/file/src/Plugin/views/field/Uri.php b/core/modules/file/src/Plugin/views/field/Uri.php
index 04497b1..2d2c481 100644
--- a/core/modules/file/src/Plugin/views/field/Uri.php
+++ b/core/modules/file/src/Plugin/views/field/Uri.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\file\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -22,7 +23,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['file_download_path'] = array(
       '#title' => t('Display download path instead of file storage URI'),
       '#description' => t('This will provide the full download URL rather than the internal filestream address.'),
diff --git a/core/modules/file/tests/file_module_test/src/Form/FileModuleTestForm.php b/core/modules/file/tests/file_module_test/src/Form/FileModuleTestForm.php
index 84b2760..19264cc 100644
--- a/core/modules/file/tests/file_module_test/src/Form/FileModuleTestForm.php
+++ b/core/modules/file/tests/file_module_test/src/Form/FileModuleTestForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\file_module_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for file_module_test module.
@@ -26,8 +27,8 @@ public function getFormId() {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param bool $tree
    *   (optional) If the form should use #tree. Defaults to TRUE.
    * @param bool $extended
@@ -37,7 +38,7 @@ public function getFormId() {
    * @param array $default_fids
    *   (optional) Any default file IDs to use.
    */
-  public function buildForm(array $form, array &$form_state, $tree = TRUE, $extended = TRUE, $multiple = FALSE, $default_fids = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $tree = TRUE, $extended = TRUE, $multiple = FALSE, $default_fids = NULL) {
     $form['#tree'] = (bool) $tree;
 
     $form['nested']['file'] = array(
@@ -70,7 +71,7 @@ public function buildForm(array $form, array &$form_state, $tree = TRUE, $extend
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($form['#tree']) {
       $uploads = $form_state['values']['nested']['file'];
     }
diff --git a/core/modules/file/tests/file_test/src/Form/FileTestForm.php b/core/modules/file/tests/file_test/src/Form/FileTestForm.php
index f2d6dc2..68ebf61 100644
--- a/core/modules/file/tests/file_test/src/Form/FileTestForm.php
+++ b/core/modules/file/tests/file_test/src/Form/FileTestForm.php
@@ -7,6 +7,7 @@
 namespace Drupal\file_test\Form;
 
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * File test form class.
@@ -23,7 +24,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['file_test_upload'] = array(
       '#type' => 'file',
       '#title' => t('Upload a file'),
@@ -72,12 +73,12 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {}
+  public function validateForm(array &$form, FormStateInterface $form_state) {}
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Process the upload and perform validation. Note: we're using the
     // form value for the $replace parameter.
     if (!empty($form_state['values']['file_subdir'])) {
diff --git a/core/modules/filter/src/Entity/FilterFormat.php b/core/modules/filter/src/Entity/FilterFormat.php
index 944d5c7..6f2be4d 100644
--- a/core/modules/filter/src/Entity/FilterFormat.php
+++ b/core/modules/filter/src/Entity/FilterFormat.php
@@ -97,7 +97,7 @@ class FilterFormat extends ConfigEntityBase implements FilterFormatInterface, En
    *
    * An associative array of filters assigned to the text format, keyed by the
    * instance ID of each filter and using the properties:
-   * - plugin_id: The plugin ID of the filter plugin instance.
+   * - id: The plugin ID of the filter plugin instance.
    * - module: The name of the module providing the filter.
    * - status: (optional) A Boolean indicating whether the filter is
    *   enabled in the text format. Defaults to FALSE.
@@ -193,9 +193,6 @@ public function preSave(EntityStorageInterface $storage) {
     parent::preSave($storage);
 
     $this->name = trim($this->label());
-
-    // @todo Do not save disabled filters whose properties are identical to
-    //   all default properties.
   }
 
   /**
diff --git a/core/modules/filter/src/FilterBag.php b/core/modules/filter/src/FilterBag.php
index 970e7e8..f509847 100644
--- a/core/modules/filter/src/FilterBag.php
+++ b/core/modules/filter/src/FilterBag.php
@@ -107,4 +107,26 @@ public function sortHelper($aID, $bID) {
     return parent::sortHelper($aID, $bID);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfiguration() {
+    $configuration = parent::getConfiguration();
+    // Remove configuration if it matches the defaults. In self::getAll(), we
+    // load all available filters, in addition to the enabled filters stored in
+    // configuration. In order to prevent those from bleeding through to the
+    // stored configuration, remove all filters that match the default values.
+    // Because filters are disabled by default, this will never remove the
+    // configuration of an enabled filter.
+    foreach ($configuration as $instance_id => $instance_config) {
+      $default_config = array();
+      $default_config['id'] = $instance_id;
+      $default_config += $this->get($instance_id)->defaultConfiguration();
+      if ($default_config === $instance_config) {
+        unset($configuration[$instance_id]);
+      }
+    }
+    return $configuration;
+  }
+
 }
diff --git a/core/modules/filter/src/FilterFormatAddForm.php b/core/modules/filter/src/FilterFormatAddForm.php
index 5a0e83e..8c6ad4a 100644
--- a/core/modules/filter/src/FilterFormatAddForm.php
+++ b/core/modules/filter/src/FilterFormatAddForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\filter;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a form for adding a filter format.
  */
@@ -15,14 +17,14 @@ class FilterFormatAddForm extends FilterFormatFormBase {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     return parent::form($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
     drupal_set_message($this->t('Added text format %format.', array('%format' => $this->entity->label())));
     return $this->entity;
diff --git a/core/modules/filter/src/FilterFormatEditForm.php b/core/modules/filter/src/FilterFormatEditForm.php
index a1448a0..ab437ac 100644
--- a/core/modules/filter/src/FilterFormatEditForm.php
+++ b/core/modules/filter/src/FilterFormatEditForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 /**
@@ -17,7 +18,7 @@ class FilterFormatEditForm extends FilterFormatFormBase {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     if (!$this->entity->status()) {
       throw new NotFoundHttpException();
     }
@@ -31,7 +32,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
     drupal_set_message($this->t('The text format %format has been updated.', array('%format' => $this->entity->label())));
     return $this->entity;
diff --git a/core/modules/filter/src/FilterFormatFormBase.php b/core/modules/filter/src/FilterFormatFormBase.php
index 7a23b93..fce0b93 100644
--- a/core/modules/filter/src/FilterFormatFormBase.php
+++ b/core/modules/filter/src/FilterFormatFormBase.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\filter\Plugin\Filter\FilterNull;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -47,7 +48,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $format = $this->entity;
     $is_fallback = ($format->id() == $this->config('filter.settings')->get('fallback_format'));
 
@@ -209,7 +210,7 @@ public function exists($format_id) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     // @todo Move trimming upstream.
@@ -233,7 +234,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     // Add the submitted form values to the text format, and save it.
@@ -265,7 +266,7 @@ public function submit(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Save configuration');
     return $actions;
diff --git a/core/modules/filter/src/FilterFormatListBuilder.php b/core/modules/filter/src/FilterFormatListBuilder.php
index 4f1a5cb..0003cfa 100644
--- a/core/modules/filter/src/FilterFormatListBuilder.php
+++ b/core/modules/filter/src/FilterFormatListBuilder.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -136,15 +137,16 @@ public function getDefaultOperations(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
     $form['actions']['submit']['#value'] = $this->t('Save changes');
     return $form;
   }
+
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     filter_formats_reset();
diff --git a/core/modules/filter/src/Form/FilterDisableForm.php b/core/modules/filter/src/Form/FilterDisableForm.php
index af66159..a6b7b88 100644
--- a/core/modules/filter/src/Form/FilterDisableForm.php
+++ b/core/modules/filter/src/Form/FilterDisableForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\filter\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -46,7 +47,7 @@ public function getDescription() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->disable()->save();
     drupal_set_message($this->t('Disabled text format %format.', array('%format' => $this->entity->label())));
 
diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtml.php b/core/modules/filter/src/Plugin/Filter/FilterHtml.php
index 6549168..b76933e 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterHtml.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterHtml.php
@@ -8,6 +8,7 @@
 namespace Drupal\filter\Plugin\Filter;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\filter\FilterProcessResult;
 use Drupal\filter\Plugin\FilterBase;
 
@@ -31,7 +32,7 @@ class FilterHtml extends FilterBase {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $form['allowed_html'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('Allowed HTML tags'),
diff --git a/core/modules/filter/src/Plugin/Filter/FilterUrl.php b/core/modules/filter/src/Plugin/Filter/FilterUrl.php
index d717f2c..a915052 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterUrl.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterUrl.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter\Plugin\Filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\filter\FilterProcessResult;
 use Drupal\filter\Plugin\FilterBase;
 
@@ -27,7 +28,7 @@ class FilterUrl extends FilterBase {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $form['filter_url_length'] = array(
       '#type' => 'number',
       '#title' => $this->t('Maximum link text length'),
diff --git a/core/modules/filter/src/Plugin/FilterBase.php b/core/modules/filter/src/Plugin/FilterBase.php
index cfed8ac..de9613f 100644
--- a/core/modules/filter/src/Plugin/FilterBase.php
+++ b/core/modules/filter/src/Plugin/FilterBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter\Plugin;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginBase;
 
 /**
@@ -107,7 +108,12 @@ public function getConfiguration() {
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
-    return array();
+    return array(
+      'provider' => $this->pluginDefinition['provider'],
+      'status' => FALSE,
+      'weight' => $this->pluginDefinition['weight'] ?: 0,
+      'settings' => $this->pluginDefinition['settings'],
+    );
   }
 
   /**
@@ -141,7 +147,7 @@ public function getDescription() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     // Implementations should work with and return $form. Returning an empty
     // array here allows the text format administration form to identify whether
     // the filter plugin has any settings form elements.
diff --git a/core/modules/filter/src/Plugin/FilterInterface.php b/core/modules/filter/src/Plugin/FilterInterface.php
index dbbc490..aa2438b 100644
--- a/core/modules/filter/src/Plugin/FilterInterface.php
+++ b/core/modules/filter/src/Plugin/FilterInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines the interface for text processing filter plugins.
@@ -132,14 +133,14 @@ public function getDescription();
    *
    * @param array $form
    *   A minimally prepopulated form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The state of the (entire) configuration form.
    *
    * @return array
    *   The $form array with additional form elements for the settings of this
    *   filter. The submitted form values should match $this->settings.
    */
-  public function settingsForm(array $form, array &$form_state);
+  public function settingsForm(array $form, FormStateInterface $form_state);
 
   /**
    * Prepares the text for processing.
diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php
index 9e52420..f575ec3 100644
--- a/core/modules/filter/src/Tests/FilterAPITest.php
+++ b/core/modules/filter/src/Tests/FilterAPITest.php
@@ -329,6 +329,50 @@ function testTypedDataAPI() {
   }
 
   /**
+   * Tests that FilterFormat::preSave() only saves customized plugins.
+   */
+  public function testFilterFormatPreSave() {
+    /** @var \Drupal\filter\FilterFormatInterface $crazy_format */
+    $crazy_format = entity_create('filter_format', array(
+      'format' => 'crazy',
+      'name' => 'Crazy',
+      'weight' => 1,
+      'filters' => array(
+        'filter_html_escape' => array(
+          'weight' => 10,
+          'status' => 1,
+        ),
+        'filter_html' => array(
+          'weight' => -10,
+          'status' => 1,
+          'settings' => array(
+            'allowed_html' => '<p>',
+          ),
+        ),
+      )
+    ));
+    $crazy_format->save();
+    // Use config to directly load the configuration and check that only enabled
+    // or customized plugins are saved to configuration.
+    $filters = \Drupal::config('filter.format.crazy')->get('filters');
+    $this->assertEqual(array('filter_html_escape', 'filter_html'), array_keys($filters));
+
+    // Disable a plugin to ensure that disabled plugins with custom settings are
+    // stored in configuration.
+    $crazy_format->setFilterConfig('filter_html_escape', array('status' => FALSE));
+    $crazy_format->save();
+    $filters = \Drupal::config('filter.format.crazy')->get('filters');
+    $this->assertEqual(array('filter_html_escape', 'filter_html'), array_keys($filters));
+
+    // Set the settings as per default to ensure that disable plugins in this
+    // state are not stored in configuration.
+    $crazy_format->setFilterConfig('filter_html_escape', array('weight' => -10));
+    $crazy_format->save();
+    $filters = \Drupal::config('filter.format.crazy')->get('filters');
+    $this->assertEqual(array('filter_html'), array_keys($filters));
+  }
+
+  /**
    * Checks if an expected violation exists in the given violations.
    *
    * @param \Symfony\Component\Validator\ConstraintViolationListInterface $violations
diff --git a/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php b/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php
index be8cd12..8f90746 100644
--- a/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php
+++ b/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php
@@ -7,6 +7,7 @@
 namespace Drupal\filter_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Shows a test form for testing the 'text_format' form element.
@@ -23,7 +24,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // This ensures that the parent array key makes it into the HTML ID of the
     // form elements.
     $form['#tree'] = TRUE;
@@ -109,7 +110,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 32443a9..425b597 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -198,7 +199,7 @@ function forum_uri($forum) {
  * Checks in particular that the node is assigned only a "leaf" term in the
  * forum taxonomy.
  */
-function forum_node_validate(EntityInterface $node, $form, &$form_state) {
+function forum_node_validate(EntityInterface $node, $form, FormStateInterface $form_state) {
   if (\Drupal::service('forum_manager')->checkNodeType($node)) {
     // vocabulary is selected, not a "container" term.
     if (!$node->taxonomy_forums->isEmpty()) {
@@ -384,7 +385,7 @@ function forum_comment_delete(CommentInterface $comment) {
 /**
  * Implements hook_form_BASE_FORM_ID_alter().
  */
-function forum_form_taxonomy_vocabulary_form_alter(&$form, &$form_state, $form_id) {
+function forum_form_taxonomy_vocabulary_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $vid = \Drupal::config('forum.settings')->get('vocabulary');
   $vocabulary = $form_state['controller']->getEntity();
   if ($vid == $vocabulary->id()) {
@@ -406,7 +407,7 @@ function forum_form_taxonomy_vocabulary_form_alter(&$form, &$form_state, $form_i
 /**
  * Implements hook_form_FORM_ID_alter() for taxonomy_term_form().
  */
-function forum_form_taxonomy_term_form_alter(&$form, &$form_state, $form_id) {
+function forum_form_taxonomy_term_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $vid = \Drupal::config('forum.settings')->get('vocabulary');
   if (isset($form['vid']['#value']) && $form['vid']['#value'] == $vid) {
     // Hide multiple parents select from forum terms.
@@ -417,7 +418,7 @@ function forum_form_taxonomy_term_form_alter(&$form, &$form_state, $form_id) {
 /**
  * Implements hook_form_BASE_FORM_ID_alter() for node_form().
  */
-function forum_form_node_form_alter(&$form, &$form_state, $form_id) {
+function forum_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $node = $form_state['controller']->getEntity();
   if (isset($node->taxonomy_forums) && !$node->isNew()) {
     $forum_terms = $node->taxonomy_forums;
diff --git a/core/modules/forum/src/Form/ContainerForm.php b/core/modules/forum/src/Form/ContainerForm.php
index 1918bd0..e167d74 100644
--- a/core/modules/forum/src/Form/ContainerForm.php
+++ b/core/modules/forum/src/Form/ContainerForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\forum\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Base form for container term edit forms.
  */
@@ -22,7 +24,7 @@ class ContainerForm extends ForumForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $taxonomy_term = $this->entity;
     // Build the bulk of the form from the parent forum form.
     $form = parent::form($form, $form_state, $taxonomy_term);
@@ -40,7 +42,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $is_new = $this->entity->isNew();
     $this->entity->forum_container = TRUE;
     $term = parent::save($form, $form_state);
diff --git a/core/modules/forum/src/Form/DeleteForm.php b/core/modules/forum/src/Form/DeleteForm.php
index 6071fb8..94cdf11 100644
--- a/core/modules/forum/src/Form/DeleteForm.php
+++ b/core/modules/forum/src/Form/DeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\forum\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\taxonomy\TermInterface;
 
@@ -54,7 +55,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, TermInterface $taxonomy_term = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, TermInterface $taxonomy_term = NULL) {
     $this->taxonomyTerm = $taxonomy_term;
 
     return parent::buildForm($form, $form_state);
@@ -63,7 +64,7 @@ public function buildForm(array $form, array &$form_state, TermInterface $taxono
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->taxonomyTerm->delete();
     drupal_set_message($this->t('The forum %label and all sub-forums have been deleted.', array('%label' => $this->taxonomyTerm->label())));
     watchdog('forum', 'forum: deleted %label and all its sub-forums.', array('%label' => $this->taxonomyTerm->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/forum/src/Form/ForumForm.php b/core/modules/forum/src/Form/ForumForm.php
index fc20134..3007380 100644
--- a/core/modules/forum/src/Form/ForumForm.php
+++ b/core/modules/forum/src/Form/ForumForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\forum\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\taxonomy\TermForm;
 
 /**
@@ -31,7 +32,7 @@ class ForumForm extends TermForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $taxonomy_term = $this->entity;
     // Build the bulk of the form from the parent taxonomy term form.
     $form = parent::form($form, $form_state, $taxonomy_term);
@@ -61,7 +62,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     $term = parent::buildEntity($form, $form_state);
 
     // Assign parents from forum parent select field.
@@ -73,7 +74,7 @@ public function buildEntity(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $term = $this->entity;
     $term_storage = $this->entityManager->getStorage('taxonomy_term');
     $status = $term_storage->save($term);
@@ -98,7 +99,7 @@ public function save(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
 
     if (!$this->entity->isNew() && $this->entity->hasLinkTemplate('forum-delete-form')) {
diff --git a/core/modules/forum/src/Form/Overview.php b/core/modules/forum/src/Form/Overview.php
index 98c3feb..98688ab 100644
--- a/core/modules/forum/src/Form/Overview.php
+++ b/core/modules/forum/src/Form/Overview.php
@@ -8,6 +8,7 @@
 namespace Drupal\forum\Form;
 
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\taxonomy\Form\OverviewTerms;
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -60,7 +61,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $forum_config = $this->config('forum.settings');
     $vid = $forum_config->get('vocabulary');
     $vocabulary = $this->entityManager->getStorage('taxonomy_vocabulary')->load($vid);
diff --git a/core/modules/forum/src/ForumSettingsForm.php b/core/modules/forum/src/ForumSettingsForm.php
index dbe486f..51b42a3 100644
--- a/core/modules/forum/src/ForumSettingsForm.php
+++ b/core/modules/forum/src/ForumSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\forum;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure forum settings for this site.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('forum.settings');
 
     $options = array(5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 80, 100, 150, 200, 250, 300, 350, 400, 500);
@@ -63,7 +64,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('forum.settings')
       ->set('topics.hot_threshold', $form_state['values']['forum_hot_topic'])
       ->set('topics.page_limit', $form_state['values']['forum_per_page'])
diff --git a/core/modules/forum/src/Plugin/Block/ForumBlockBase.php b/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
index 6a5b492..b9bab02 100644
--- a/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
+++ b/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\forum\Plugin\Block;
 
 use Drupal\block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Cache\Cache;
 
@@ -61,9 +62,9 @@ protected function blockAccess(AccountInterface $account) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockForm().
+   * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     $range = range(2, 20);
     $form['block_count'] = array(
       '#type' => 'select',
@@ -75,9 +76,9 @@ public function blockForm($form, &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['block_count'] = $form_state['values']['block_count'];
   }
 
diff --git a/core/modules/help/src/Controller/HelpController.php b/core/modules/help/src/Controller/HelpController.php
index 26a3160..437c3a8 100644
--- a/core/modules/help/src/Controller/HelpController.php
+++ b/core/modules/help/src/Controller/HelpController.php
@@ -125,8 +125,7 @@ public function helpPage($name) {
       if (!empty($admin_tasks)) {
         $links = array();
         foreach ($admin_tasks as $task) {
-          $link = $task['localized_options'];
-          $link['href'] = $task['link_path'];
+          $link = $task['url']->toArray();
           $link['title'] = $task['title'];
           $links[] = $link;
         }
diff --git a/core/modules/history/src/Plugin/views/field/HistoryUserTimestamp.php b/core/modules/history/src/Plugin/views/field/HistoryUserTimestamp.php
index ca9a276..4a7d0c1 100644
--- a/core/modules/history/src/Plugin/views/field/HistoryUserTimestamp.php
+++ b/core/modules/history/src/Plugin/views/field/HistoryUserTimestamp.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\history\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -54,7 +55,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     if (\Drupal::moduleHandler()->moduleExists('comment')) {
       $form['comments'] = array(
diff --git a/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php b/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php
index 0648fec..70866c8 100644
--- a/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php
+++ b/core/modules/history/src/Plugin/views/filter/HistoryUserTimestamp.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\history\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 
 /**
@@ -31,7 +32,7 @@ public function usesGroupBy() {
     return FALSE;
   }
 
-  public function buildExposeForm(&$form, &$form_state) {
+  public function buildExposeForm(&$form, FormStateInterface $form_state) {
     parent::buildExposeForm($form, $form_state);
     // @todo There are better ways of excluding required and multiple (object flags)
     unset($form['expose']['required']);
@@ -39,7 +40,7 @@ public function buildExposeForm(&$form, &$form_state) {
     unset($form['expose']['remember']);
   }
 
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     // Only present a checkbox for the exposed filter itself. There's no way
     // to tell the difference between not checked and the default value, so
     // specifying the default value via the views UI is meaningless.
diff --git a/core/modules/image/src/ConfigurableImageEffectBase.php b/core/modules/image/src/ConfigurableImageEffectBase.php
index ce42164..7b391b5 100644
--- a/core/modules/image/src/ConfigurableImageEffectBase.php
+++ b/core/modules/image/src/ConfigurableImageEffectBase.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\image;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a base class for configurable image effects.
  */
@@ -15,13 +17,13 @@
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/image/src/Form/ImageEffectAddForm.php b/core/modules/image/src/Form/ImageEffectAddForm.php
index 1efeab1..e491d07 100644
--- a/core/modules/image/src/Form/ImageEffectAddForm.php
+++ b/core/modules/image/src/Form/ImageEffectAddForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Form;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\ImageEffectManager;
 use Drupal\image\ImageStyleInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -46,7 +47,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
     $form = parent::buildForm($form, $form_state, $image_style, $image_effect);
 
     $form['#title'] = $this->t('Add %label effect', array('%label' => $this->imageEffect->label()));
diff --git a/core/modules/image/src/Form/ImageEffectDeleteForm.php b/core/modules/image/src/Form/ImageEffectDeleteForm.php
index c925da8..761fd21 100644
--- a/core/modules/image/src/Form/ImageEffectDeleteForm.php
+++ b/core/modules/image/src/Form/ImageEffectDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\ImageStyleInterface;
 
 /**
@@ -60,7 +61,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
     $this->imageStyle = $image_style;
     $this->imageEffect = $this->imageStyle->getEffect($image_effect);
 
@@ -70,7 +71,7 @@ public function buildForm(array $form, array &$form_state, ImageStyleInterface $
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->imageStyle->deleteImageEffect($this->imageEffect);
     drupal_set_message($this->t('The image effect %name has been deleted.', array('%name' => $this->imageEffect->label())));
     $form_state['redirect_route'] = $this->imageStyle->urlInfo('edit-form');
diff --git a/core/modules/image/src/Form/ImageEffectEditForm.php b/core/modules/image/src/Form/ImageEffectEditForm.php
index f949e6c..1e2ba85 100644
--- a/core/modules/image/src/Form/ImageEffectEditForm.php
+++ b/core/modules/image/src/Form/ImageEffectEditForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\image\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\ImageStyleInterface;
 
 /**
@@ -17,7 +18,7 @@ class ImageEffectEditForm extends ImageEffectFormBase {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
     $form = parent::buildForm($form, $form_state, $image_style, $image_effect);
 
     $form['#title'] = $this->t('Edit %label effect', array('%label' => $this->imageEffect->label()));
diff --git a/core/modules/image/src/Form/ImageEffectFormBase.php b/core/modules/image/src/Form/ImageEffectFormBase.php
index 6cc8d1d..6f3268e 100644
--- a/core/modules/image/src/Form/ImageEffectFormBase.php
+++ b/core/modules/image/src/Form/ImageEffectFormBase.php
@@ -8,6 +8,8 @@
 namespace Drupal\image\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\ConfigurableImageEffectInterface;
 use Drupal\image\ImageStyleInterface;
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
@@ -53,7 +55,7 @@ public function getFormId() {
    *
    * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
    */
-  public function buildForm(array $form, array &$form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ImageStyleInterface $image_style = NULL, $image_effect = NULL) {
     $this->imageStyle = $image_style;
     try {
       $this->imageEffect = $this->prepareImageEffect($image_effect);
@@ -101,27 +103,32 @@ public function buildForm(array $form, array &$form_state, ImageStyleInterface $
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // The image effect configuration is stored in the 'data' key in the form,
     // pass that through for validation.
-    $effect_data = array(
-      'values' => &$form_state['values']['data']
-    );
+    $effect_data = new FormState(array(
+      'values' => $form_state['values']['data'],
+    ));
     $this->imageEffect->validateConfigurationForm($form, $effect_data);
+    // Update the original form values.
+    $form_state['values']['data'] = $effect_data['values'];
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     form_state_values_clean($form_state);
 
     // The image effect configuration is stored in the 'data' key in the form,
     // pass that through for submission.
-    $effect_data = array(
-      'values' => &$form_state['values']['data']
-    );
+    $effect_data = new FormState(array(
+      'values' => $form_state['values']['data'],
+    ));
     $this->imageEffect->submitConfigurationForm($form, $effect_data);
+    // Update the original form values.
+    $form_state['values']['data'] = $effect_data['values'];
+
     $this->imageEffect->setWeight($form_state['values']['weight']);
     if (!$this->imageEffect->getUuid()) {
       $this->imageStyle->addImageEffect($this->imageEffect->getConfiguration());
diff --git a/core/modules/image/src/Form/ImageStyleAddForm.php b/core/modules/image/src/Form/ImageStyleAddForm.php
index 64c2a37..7d34a1d 100644
--- a/core/modules/image/src/Form/ImageStyleAddForm.php
+++ b/core/modules/image/src/Form/ImageStyleAddForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\image\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Controller for image style addition forms.
  */
@@ -15,7 +17,7 @@ class ImageStyleAddForm extends ImageStyleFormBase {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     parent::save($form, $form_state);
     drupal_set_message($this->t('Style %name was created.', array('%name' => $this->entity->label())));
   }
@@ -23,7 +25,7 @@ public function save(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function actions(array $form, array &$form_state) {
+  public function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Create new style');
 
diff --git a/core/modules/image/src/Form/ImageStyleDeleteForm.php b/core/modules/image/src/Form/ImageStyleDeleteForm.php
index 20f393b..41ca653 100644
--- a/core/modules/image/src/Form/ImageStyleDeleteForm.php
+++ b/core/modules/image/src/Form/ImageStyleDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -46,7 +47,7 @@ public function getDescription() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $replacement_styles = array_diff_key(image_style_options(), array($this->entity->id() => ''));
     $form['replacement'] = array(
       '#title' => $this->t('Replacement style'),
@@ -61,7 +62,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->set('replacementID', $form_state['values']['replacement']);
     $this->entity->delete();
     drupal_set_message($this->t('Style %name was deleted.', array('%name' => $this->entity->label())));
diff --git a/core/modules/image/src/Form/ImageStyleEditForm.php b/core/modules/image/src/Form/ImageStyleEditForm.php
index 8b27119..f861ef1 100644
--- a/core/modules/image/src/Form/ImageStyleEditForm.php
+++ b/core/modules/image/src/Form/ImageStyleEditForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\ConfigurableImageEffectInterface;
 use Drupal\image\ImageEffectManager;
 use Drupal\Component\Utility\String;
@@ -52,7 +53,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Edit style %name', array('%name' => $this->entity->label()));
     $form['#tree'] = TRUE;
     $form['#attached']['css'][drupal_get_path('module', 'image') . '/css/image.admin.css'] = array();
@@ -155,7 +156,7 @@ public function form(array $form, array &$form_state) {
   /**
    * Validate handler for image effect.
    */
-  public function effectValidate($form, &$form_state) {
+  public function effectValidate($form, FormStateInterface $form_state) {
     if (!$form_state['values']['new']) {
       $this->setFormError('new', $form_state, $this->t('Select an effect to add.'));
     }
@@ -164,7 +165,7 @@ public function effectValidate($form, &$form_state) {
   /**
    * Submit handler for image effect.
    */
-  public function effectSave($form, &$form_state) {
+  public function effectSave($form, FormStateInterface $form_state) {
 
     // Update image effect weights.
     if (!empty($form_state['values']['effects'])) {
@@ -214,7 +215,7 @@ public function effectSave($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
 
     // Update image effect weights.
     if (!empty($form_state['values']['effects'])) {
@@ -228,7 +229,7 @@ public function save(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function actions(array $form, array &$form_state) {
+  public function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Update style');
 
@@ -253,7 +254,7 @@ protected function updateEffectWeights(array $effects) {
   /**
    * {@inheritdoc}
    */
-  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, array &$form_state) {
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
     foreach ($form_state['values'] as $key => $value) {
       // Do not copy effects here, see self::updateEffectWeights().
       if ($key != 'effects') {
diff --git a/core/modules/image/src/Form/ImageStyleFlushForm.php b/core/modules/image/src/Form/ImageStyleFlushForm.php
index 9839a8a..5212ba0 100644
--- a/core/modules/image/src/Form/ImageStyleFlushForm.php
+++ b/core/modules/image/src/Form/ImageStyleFlushForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -46,7 +47,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->flush();
     drupal_set_message($this->t('The image style %name has been flushed.', array('%name' => $this->entity->label())));
     $form_state['redirect_route'] = $this->getCancelUrl();
diff --git a/core/modules/image/src/Form/ImageStyleFormBase.php b/core/modules/image/src/Form/ImageStyleFormBase.php
index efac805..ad4ce5c 100644
--- a/core/modules/image/src/Form/ImageStyleFormBase.php
+++ b/core/modules/image/src/Form/ImageStyleFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -52,7 +53,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
 
     $form['label'] = array(
       '#type' => 'textfield',
@@ -75,7 +76,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $this->entity->save();
     $form_state['redirect_route'] = $this->entity->urlInfo('edit-form');
   }
diff --git a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php
index c14ab91..069178d 100644
--- a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php
+++ b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Plugin\Field\FieldFormatter;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'image' formatter.
@@ -35,7 +36,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $image_styles = image_style_options(FALSE);
     $element['image_style'] = array(
       '#title' => t('Image style'),
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index c2e8737..d1489c8 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\file\Plugin\Field\FieldType\FileItem;
 
@@ -152,7 +153,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element = array();
 
     // We need the field-level 'default_image' setting, and $this->getSettings()
@@ -182,7 +183,7 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     // Get base form from FileItem::instanceSettingsForm().
     $element = parent::instanceSettingsForm($form, $form_state);
 
@@ -313,7 +314,7 @@ public function preSave() {
   /**
    * Element validate function for resolution fields.
    */
-  public static function validateResolution($element, &$form_state) {
+  public static function validateResolution($element, FormStateInterface $form_state) {
     if (!empty($element['x']['#value']) || !empty($element['y']['#value'])) {
       foreach (array('x', 'y') as $dimension) {
         if (!$element[$dimension]['#value']) {
@@ -383,10 +384,10 @@ protected function defaultImageForm(array &$element, array $settings) {
    *
    * @param array $element
    *   The form element to process.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public static function validateDefaultImageForm(array &$element, array &$form_state) {
+  public static function validateDefaultImageForm(array &$element, FormStateInterface $form_state) {
     // Consolidate the array value of this field to a single FID as #extended
     // for default image is not TRUE and this is a single value.
     if (isset($element['fids']['#value'][0])) {
diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
index 0ba9e7e..c38ccba 100644
--- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
+++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\file\Plugin\Field\FieldWidget\FileWidget;
 
 /**
@@ -37,7 +38,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element = parent::settingsForm($form, $form_state);
 
     $element['preview_image_style'] = array(
@@ -82,7 +83,7 @@ public function settingsSummary() {
    *
    * Special handling for draggable multiple widgets and 'add more' button.
    */
-  protected function formMultipleElements(FieldItemListInterface $items, array &$form, array &$form_state) {
+  protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
     $elements = parent::formMultipleElements($items, $form, $form_state);
 
     $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
@@ -109,7 +110,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element = parent::formElement($items, $delta, $element, $form, $form_state);
 
     $field_settings = $this->getFieldSettings();
@@ -144,7 +145,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
    *
    * This method is assigned as a #process callback in formElement() method.
    */
-  public static function process($element, &$form_state, $form) {
+  public static function process($element, FormStateInterface $form_state, $form) {
     $item = $element['#value'];
     $item['fids'] = $element['fids']['#value'];
 
@@ -227,7 +228,7 @@ public static function process($element, &$form_state, $form) {
    * This is separated in a validate function instead of a #required flag to
    * avoid being validated on the process callback.
    */
-  public static function validateRequiredFields($element, &$form_state) {
+  public static function validateRequiredFields($element, FormStateInterface $form_state) {
     // Only do validation if the function is triggered from other places than
     // the image process form.
     if (!in_array('file_managed_file_submit', $form_state['triggering_element']['#submit'])) {
diff --git a/core/modules/image/src/Plugin/ImageEffect/CropImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/CropImageEffect.php
index 42f6561..0edac98 100644
--- a/core/modules/image/src/Plugin/ImageEffect/CropImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/CropImageEffect.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\image\Plugin\ImageEffect;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Image\ImageInterface;
 
 /**
@@ -59,7 +60,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
     $form['anchor'] = array(
       '#type' => 'radios',
diff --git a/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php
index f7d495d..15f0080 100644
--- a/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\image\Plugin\ImageEffect;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Image\ImageInterface;
 use Drupal\image\ConfigurableImageEffectBase;
 
@@ -67,7 +68,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['width'] = array(
       '#type' => 'number',
       '#title' => t('Width'),
@@ -90,7 +91,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     parent::submitConfigurationForm($form, $form_state);
 
     $this->configuration['height'] = $form_state['values']['height'];
diff --git a/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
index 49529cd..7f29aaf 100644
--- a/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\image\Plugin\ImageEffect;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Image\ImageInterface;
 use Drupal\Core\Utility\Color;
 use Drupal\image\ConfigurableImageEffectBase;
@@ -97,7 +98,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['degrees'] = array(
       '#type' => 'number',
       '#default_value' => $this->configuration['degrees'],
@@ -126,7 +127,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
     if (!Color::validateHex($form_state['values']['bgcolor'])) {
       form_set_error('bgcolor', $form_state, $this->t('Background color must be a hexadecimal color value.'));
     }
@@ -135,7 +136,7 @@ public function validateConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     parent::submitConfigurationForm($form, $form_state);
 
     $this->configuration['degrees'] = $form_state['values']['degrees'];
diff --git a/core/modules/image/src/Plugin/ImageEffect/ScaleImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ScaleImageEffect.php
index e1d8ec5..a5dae9a 100644
--- a/core/modules/image/src/Plugin/ImageEffect/ScaleImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/ScaleImageEffect.php
@@ -8,6 +8,7 @@
 namespace Drupal\image\Plugin\ImageEffect;
 
 use Drupal\Component\Utility\Image;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Image\ImageInterface;
 
 /**
@@ -66,7 +67,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
     $form['width']['#required'] = FALSE;
     $form['height']['#required'] = FALSE;
@@ -82,7 +83,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
     parent::validateConfigurationForm($form, $form_state);
     if (empty($form_state['values']['width']) && empty($form_state['values']['height'])) {
       form_set_error('data', $form_state, $this->t('Width and height can not both be blank.'));
@@ -92,7 +93,7 @@ public function validateConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     parent::submitConfigurationForm($form, $form_state);
 
     $this->configuration['upscale'] = $form_state['values']['upscale'];
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 5ac331b..0909511 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -5,6 +5,7 @@
  * Add language handling functionality to Drupal.
  */
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\PhpStorage\PhpStorageFactory;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -214,7 +215,7 @@ function language_configuration_element_default_options() {
 /**
  * Process handler for the language_configuration form element.
  */
-function language_configuration_element_process($element, &$form_state, &$form) {
+function language_configuration_element_process($element, FormStateInterface $form_state, &$form) {
   $options = isset($element['#options']) ? $element['#options'] : array();
   // Avoid validation failure since we are moving the '#options' key in the
   // nested 'language' select element.
@@ -265,7 +266,7 @@ function language_configuration_element_process($element, &$form_state, &$form)
 /**
  * Submit handler for the forms that have a language_configuration element.
  */
-function language_configuration_element_submit(&$form, &$form_state) {
+function language_configuration_element_submit(&$form, FormStateInterface $form_state) {
   // Iterate through all the language_configuration elements and save their
   // values.
   if (isset($form_state['language'])) {
@@ -650,7 +651,7 @@ function language_set_browser_drupal_langcode_mappings($mappings) {
  *
  * @see language_system_regional_settings_form_submit()
  */
-function language_form_system_regional_settings_alter(&$form, &$form_state) {
+function language_form_system_regional_settings_alter(&$form, FormStateInterface $form_state) {
   $languages = \Drupal::languageManager()->getLanguages();
   $default = \Drupal::languageManager()->getDefaultLanguage();
   foreach ($languages as $key => $language) {
@@ -673,7 +674,7 @@ function language_form_system_regional_settings_alter(&$form, &$form_state) {
  *
  * @see language_form_system_regional_settings_alter()
  */
-function language_system_regional_settings_form_submit($form, &$form_state) {
+function language_system_regional_settings_form_submit($form, FormStateInterface $form_state) {
   $languages = \Drupal::languageManager()->getLanguages();
   $language = $languages[$form_state['values']['site_default_language']];
   $language->default = TRUE;
diff --git a/core/modules/language/src/Form/ContentLanguageSettingsForm.php b/core/modules/language/src/Form/ContentLanguageSettingsForm.php
index 4738a18..47c136e 100644
--- a/core/modules/language/src/Form/ContentLanguageSettingsForm.php
+++ b/core/modules/language/src/Form/ContentLanguageSettingsForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -58,7 +59,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $entity_types = $this->entityManager->getDefinitions();
     $labels = array();
     $default = array();
@@ -146,7 +147,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $config = $this->config('language.settings');
     foreach ($form_state['values']['settings'] as $entity_type => $entity_settings) {
       foreach ($entity_settings as $bundle => $bundle_settings) {
diff --git a/core/modules/language/src/Form/LanguageAddForm.php b/core/modules/language/src/Form/LanguageAddForm.php
index 3eb0bc6..692cae9 100644
--- a/core/modules/language/src/Form/LanguageAddForm.php
+++ b/core/modules/language/src/Form/LanguageAddForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\language\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\language\Form\LanguageFormBase;
 use Drupal\Core\Language\Language;
 
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['#title'] = $this->t('Add language');
 
     $predefined_languages = $this->languageManager->getStandardLanguageListWithoutConfigured();
@@ -81,7 +82,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $langcode = $form_state['values']['predefined_langcode'];
     if ($langcode == 'custom') {
       $langcode = $form_state['values']['langcode'];
@@ -109,7 +110,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function actions(array $form, array &$form_state) {
+  public function actions(array $form, FormStateInterface $form_state) {
     // No actions needed.
     return array();
   }
@@ -117,7 +118,7 @@ public function actions(array $form, array &$form_state) {
   /**
    * Validates the language addition form on custom language button.
    */
-  public function validateCustom(array $form, array &$form_state) {
+  public function validateCustom(array $form, FormStateInterface $form_state) {
     if ($form_state['values']['predefined_langcode'] == 'custom') {
       $langcode = $form_state['values']['langcode'];
       // Reuse the editing form validation routine if we add a custom language.
@@ -135,7 +136,7 @@ public function validateCustom(array $form, array &$form_state) {
   /**
    * Element specific validator for the Add language button.
    */
-  public function validatePredefined($form, &$form_state) {
+  public function validatePredefined($form, FormStateInterface $form_state) {
     $langcode = $form_state['values']['predefined_langcode'];
     if ($langcode == 'custom') {
       $this->setFormError('predefined_langcode', $form_state, $this->t('Fill in the language details and save the language with <em>Add custom language</em>.'));
diff --git a/core/modules/language/src/Form/LanguageDeleteForm.php b/core/modules/language/src/Form/LanguageDeleteForm.php
index 8ef8aec..db158e0 100644
--- a/core/modules/language/src/Form/LanguageDeleteForm.php
+++ b/core/modules/language/src/Form/LanguageDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\language\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -84,7 +85,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $langcode = $this->entity->id();
 
     // Warn and redirect user when attempting to delete the default language.
@@ -105,7 +106,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // @todo This should be replaced with $this->entity->delete() when the
     //   additional logic in language_delete() is ported.
     $success = language_delete($this->entity->id());
diff --git a/core/modules/language/src/Form/LanguageEditForm.php b/core/modules/language/src/Form/LanguageEditForm.php
index 2dacdc2..f5d7498 100644
--- a/core/modules/language/src/Form/LanguageEditForm.php
+++ b/core/modules/language/src/Form/LanguageEditForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\language\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\language\Form\LanguageFormBase;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $this->commonForm($form);
     return parent::form($form, $form_state);
   }
@@ -33,7 +34,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function actions(array $form, array &$form_state) {
+  public function actions(array $form, FormStateInterface $form_state) {
     $actions['submit'] = array(
       '#type' => 'submit',
       '#value' => $this->t('Save language'),
@@ -46,7 +47,7 @@ public function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Prepare a language object for saving.
     $languages = language_list();
     $langcode = $form_state['values']['langcode'];
diff --git a/core/modules/language/src/Form/LanguageFormBase.php b/core/modules/language/src/Form/LanguageFormBase.php
index 583787a..880a017 100644
--- a/core/modules/language/src/Form/LanguageFormBase.php
+++ b/core/modules/language/src/Form/LanguageFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -96,7 +97,7 @@ public function commonForm(array &$form) {
   /**
    * Validates the language editing element.
    */
-  public function validateCommon(array $form, array &$form_state) {
+  public function validateCommon(array $form, FormStateInterface $form_state) {
     // Ensure sane field values for langcode and name.
     if (!isset($form['langcode_view']) && preg_match('@[^a-zA-Z_-]@', $form_state['values']['langcode'])) {
       $this->setFormError('langcode', $form_state, $this->t('%field may only contain characters a-z, underscores, or hyphens.', array('%field' => $form['langcode']['#title'])));
diff --git a/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
index 3fa4a86..43fd8b4 100644
--- a/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\language\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -47,7 +48,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $browser_langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $browser_langcode = NULL) {
     $this->browserLangcode = $browser_langcode;
 
     $form = parent::buildForm($form, $form_state);
@@ -58,7 +59,7 @@ public function buildForm(array $form, array &$form_state, $browser_langcode = N
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $mappings = language_get_browser_drupal_langcode_mappings();
 
     if (array_key_exists($this->browserLangcode, $mappings)) {
diff --git a/core/modules/language/src/Form/NegotiationBrowserForm.php b/core/modules/language/src/Form/NegotiationBrowserForm.php
index f82e54a..9d1177b 100644
--- a/core/modules/language/src/Form/NegotiationBrowserForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -55,7 +56,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = array();
 
     // Initialize a language list to the ones available, including English.
@@ -128,7 +129,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Array to check if all browser language codes are unique.
     $unique_values = array();
 
@@ -167,7 +168,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $mappings = $form_state['mappings'];
     if (!empty($mappings)) {
       $config = $this->config('language.mappings');
diff --git a/core/modules/language/src/Form/NegotiationConfigureForm.php b/core/modules/language/src/Form/NegotiationConfigureForm.php
index a6d241f..afc39aa 100644
--- a/core/modules/language/src/Form/NegotiationConfigureForm.php
+++ b/core/modules/language/src/Form/NegotiationConfigureForm.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Drupal\language\LanguageNegotiatorInterface;
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
@@ -93,7 +94,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $configurable = $this->languageTypes->get('configurable');
 
     $form = array(
@@ -127,7 +128,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $configurable_types = $form['#language_types'];
 
     $stored_values = $this->languageTypes->get('configurable');
diff --git a/core/modules/language/src/Form/NegotiationSelectedForm.php b/core/modules/language/src/Form/NegotiationSelectedForm.php
index 47d61eb..f88daa8 100644
--- a/core/modules/language/src/Form/NegotiationSelectedForm.php
+++ b/core/modules/language/src/Form/NegotiationSelectedForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\language\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Form\ConfigFormBase;
 
@@ -23,9 +24,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('language.negotiation');
     $form['selected_langcode'] = array(
       '#type' => 'language_select',
@@ -38,9 +39,9 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('language.negotiation')
       ->set('selected_langcode', $form_state['values']['selected_langcode'])
       ->save();
diff --git a/core/modules/language/src/Form/NegotiationSessionForm.php b/core/modules/language/src/Form/NegotiationSessionForm.php
index 13936af..ef4cb3d 100644
--- a/core/modules/language/src/Form/NegotiationSessionForm.php
+++ b/core/modules/language/src/Form/NegotiationSessionForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\language\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure the session language negotiation method for this site.
@@ -22,9 +23,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('language.negotiation');
     $form['language_negotiation_session_param'] = array(
       '#title' => t('Request/session parameter'),
@@ -39,9 +40,9 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('language.settings')
       ->set('session.parameter', $form_state['values']['language_negotiation_session_param'])
       ->save();
diff --git a/core/modules/language/src/Form/NegotiationUrlForm.php b/core/modules/language/src/Form/NegotiationUrlForm.php
index d8c2490..96cbbb8 100644
--- a/core/modules/language/src/Form/NegotiationUrlForm.php
+++ b/core/modules/language/src/Form/NegotiationUrlForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\language\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
 
 /**
@@ -23,9 +24,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     global $base_url;
     $config = $this->config('language.negotiation');
 
@@ -96,7 +97,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * Implements \Drupal\Core\Form\FormInterface::validateForm().
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $languages = language_list();
 
     // Count repeated values for uniqueness check.
@@ -158,9 +159,9 @@ public function validateForm(array &$form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Save selected format (prefix or domain).
     $this->config('language.negotiation')
       ->set('url.source', $form_state['values']['language_negotiation_url_part'])
diff --git a/core/modules/language/src/LanguageListBuilder.php b/core/modules/language/src/LanguageListBuilder.php
index c5bd66a..3c28810 100644
--- a/core/modules/language/src/LanguageListBuilder.php
+++ b/core/modules/language/src/LanguageListBuilder.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\Entity\DraggableListBuilder;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a class to build a listing of language entities.
@@ -75,7 +76,7 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
     $form[$this->entitiesKey]['#languages'] = $this->entities;
     $form['actions']['submit']['#value'] = t('Save configuration');
@@ -85,7 +86,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     $language_manager = \Drupal::languageManager();
diff --git a/core/modules/language/src/Plugin/Condition/Language.php b/core/modules/language/src/Plugin/Condition/Language.php
index 46a99cb..3ae2b09 100644
--- a/core/modules/language/src/Plugin/Condition/Language.php
+++ b/core/modules/language/src/Plugin/Condition/Language.php
@@ -8,6 +8,7 @@
 namespace Drupal\language\Plugin\Condition;
 
 use Drupal\Core\Condition\ConditionPluginBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
@@ -27,7 +28,7 @@ class Language extends ConditionPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     if (\Drupal::languageManager()->isMultilingual()) {
       // Fetch languages.
       $languages = language_list(LanguageInterface::STATE_ALL);
@@ -55,7 +56,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['langcodes'] = array_filter($form_state['values']['langcodes']);
     parent::submitConfigurationForm($form, $form_state);
   }
diff --git a/core/modules/language/src/Tests/LanguageConfigSchemaTest.php b/core/modules/language/src/Tests/LanguageConfigSchemaTest.php
index e4862bc..28fcad0 100644
--- a/core/modules/language/src/Tests/LanguageConfigSchemaTest.php
+++ b/core/modules/language/src/Tests/LanguageConfigSchemaTest.php
@@ -24,7 +24,7 @@ class LanguageConfigSchemaTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('language');
+  public static $modules = array('language', 'menu_link_content');
 
   /**
    * A user with administrative permissions.
@@ -55,8 +55,8 @@ function testValidLanguageConfigSchema() {
     $settings_path = 'admin/config/regional/content-language';
 
     // Enable translation for menu link.
-    $edit['entity_types[menu_link]'] = TRUE;
-    $edit['settings[menu_link][menu_link][settings][language][language_show]'] = TRUE;
+    $edit['entity_types[menu_link_content]'] = TRUE;
+    $edit['settings[menu_link_content][menu_link_content][settings][language][language_show]'] = TRUE;
 
     // Enable translation for user.
     $edit['entity_types[user]'] = TRUE;
@@ -67,7 +67,7 @@ function testValidLanguageConfigSchema() {
 
     $config_data = \Drupal::config('language.settings')->get();
     // Make sure configuration saved correctly.
-    $this->assertTrue($config_data['entities']['menu_link']['menu_link']['language']['default_configuration']['language_show']);
+    $this->assertTrue($config_data['entities']['menu_link_content']['menu_link_content']['language']['default_configuration']['language_show']);
 
     $this->assertConfigSchema(\Drupal::service('config.typed'), 'language.settings', $config_data);
   }
diff --git a/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElement.php b/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElement.php
index a213d5c..f9a0e1b 100644
--- a/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElement.php
+++ b/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElement.php
@@ -7,6 +7,7 @@
 namespace Drupal\language_elements_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * A form containing a language configuration element.
@@ -23,7 +24,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $conf = language_get_default_configuration('some_custom_type', 'some_bundle');
 
     $form['lang_configuration'] = array(
@@ -46,6 +47,6 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 }
diff --git a/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElementTest.php b/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElementTest.php
index bf53149..130c069 100644
--- a/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElementTest.php
+++ b/core/modules/language/tests/language_elements_test/src/Form/LanguageConfigurationElementTest.php
@@ -7,6 +7,7 @@
 namespace Drupal\language_elements_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * A form containing a language select element.
@@ -23,7 +24,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['langcode'] = array(
       '#title' => t('Language select'),
       '#type' => 'language_select',
@@ -35,6 +36,6 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 }
diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
index 37df049..0c08d66 100644
--- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FormatterBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\link\LinkItemInterface;
 
@@ -42,7 +43,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements = parent::settingsForm($form, $form_state);
 
     $elements['trim_length'] = array(
diff --git a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
index 850c19e..f8639bb 100644
--- a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
+++ b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemBase;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\TypedData\MapDataDefinition;
 use Drupal\link\LinkItemInterface;
@@ -104,7 +105,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
 
     $element['link_type'] = array(
diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index 27072ee..568f64c 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\Routing\MatchingRouteNotFoundException;
 use Drupal\Core\Url;
@@ -42,7 +43,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
 
     $default_url_value = NULL;
     if (isset($items[$delta]->url)) {
@@ -138,7 +139,7 @@ protected function supportsExternalLinks() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements = parent::settingsForm($form, $form_state);
 
     $elements['placeholder_url'] = array(
@@ -190,7 +191,7 @@ public function settingsSummary() {
    *
    * Conditionally requires the link title if a URL value was filled in.
    */
-  public function validateTitle(&$element, &$form_state, $form) {
+  public function validateTitle(&$element, FormStateInterface $form_state, $form) {
     if ($element['url']['#value'] !== '' && $element['title']['#value'] === '') {
       $element['title']['#required'] = TRUE;
       \Drupal::formBuilder()->setError($element['title'], $form_state, $this->t('!name field is required.', array('!name' => $element['title']['#title'])));
@@ -200,7 +201,7 @@ public function validateTitle(&$element, &$form_state, $form) {
   /**
    * {@inheritdoc}
    */
-  public function massageFormValues(array $values, array $form, array &$form_state) {
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     foreach ($values as &$value) {
       if (!empty($value['url'])) {
         try {
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 0728d07..7f40bf4 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -14,6 +14,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\StringTranslation\TranslationWrapper;
@@ -647,7 +648,7 @@ function locale_library_alter(array &$library, $name) {
 /**
  * Implements hook_form_FORM_ID_alter() for language_admin_overview_form().
  */
-function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_overview_form_alter(&$form, FormStateInterface $form_state) {
   $languages = $form['languages']['#languages'];
 
   $total_strings = \Drupal::service('locale.storage')->countStrings();
@@ -700,7 +701,7 @@ function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
 /**
  * Implements hook_form_FORM_ID_alter() for language_admin_add_form().
  */
-function locale_form_language_admin_add_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_add_form_alter(&$form, FormStateInterface $form_state) {
   $form['predefined_submit']['#submit'][] = 'locale_form_language_admin_add_form_alter_submit';
   $form['custom_language']['submit']['#submit'][] = 'locale_form_language_admin_add_form_alter_submit';
 }
@@ -736,7 +737,7 @@ function locale_form_language_admin_add_form_alter_submit($form, $form_state) {
 /**
  * Implements hook_form_FORM_ID_alter() for language_admin_edit_form().
  */
-function locale_form_language_admin_edit_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_edit_form_alter(&$form, FormStateInterface $form_state) {
   if ($form['langcode']['#type'] == 'value' && $form['langcode']['#value'] == 'en') {
     $form['locale_translate_english'] = array(
       '#title' => t('Enable interface translation to English'),
diff --git a/core/modules/locale/src/Form/ExportForm.php b/core/modules/locale/src/Form/ExportForm.php
index ea4a153..5177c69 100644
--- a/core/modules/locale/src/Form/ExportForm.php
+++ b/core/modules/locale/src/Form/ExportForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Gettext\PoStreamWriter;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\locale\PoDatabaseReader;
@@ -56,7 +57,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $languages = $this->languageManager->getLanguages();
     $language_options = array();
     foreach ($languages as $langcode => $language) {
@@ -127,7 +128,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // If template is required, language code is not given.
     if ($form_state['values']['langcode'] != LanguageInterface::LANGCODE_SYSTEM) {
       $language = $this->languageManager->getLanguage($form_state['values']['langcode']);
diff --git a/core/modules/locale/src/Form/ImportForm.php b/core/modules/locale/src/Form/ImportForm.php
index 544dc36..d74328e 100644
--- a/core/modules/locale/src/Form/ImportForm.php
+++ b/core/modules/locale/src/Form/ImportForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\Language;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -71,7 +72,7 @@ public function getFormID() {
   /**
    * Form constructor for the translation import screen.
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $languages = $this->languageManager->getLanguages();
 
     // Initialize a language list to the ones available, including English if we
@@ -157,7 +158,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $this->file = file_save_upload('file', $form['file']['#upload_validators'], 'translations://', 0);
 
     // Ensure we have the file uploaded.
@@ -169,7 +170,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Add language, if not yet supported.
     $language = $this->languageManager->getLanguage($form_state['values']['langcode']);
     if (empty($language)) {
diff --git a/core/modules/locale/src/Form/LocaleSettingsForm.php b/core/modules/locale/src/Form/LocaleSettingsForm.php
index e1b13d0..3846aaf 100644
--- a/core/modules/locale/src/Form/LocaleSettingsForm.php
+++ b/core/modules/locale/src/Form/LocaleSettingsForm.php
@@ -7,6 +7,7 @@
 namespace Drupal\locale\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure locale settings for this site.
@@ -21,9 +22,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('locale.settings');
 
     $form['update_interval_days'] = array(
@@ -83,7 +84,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * Implements \Drupal\Core\Form\FormInterface::validateForm().
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     parent::validateForm($form, $form_state);
 
     if (empty($form['#translation_directory']) && $form_state['values']['use_source'] == LOCALE_TRANSLATION_USE_SOURCE_LOCAL) {
@@ -92,9 +93,9 @@ public function validateForm(array &$form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $values = $form_state['values'];
 
     $config = $this->config('locale.settings');
diff --git a/core/modules/locale/src/Form/TranslateEditForm.php b/core/modules/locale/src/Form/TranslateEditForm.php
index c01accb..6c582d3 100644
--- a/core/modules/locale/src/Form/TranslateEditForm.php
+++ b/core/modules/locale/src/Form/TranslateEditForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\locale\Form;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\locale\SourceString;
 
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $filter_values = $this->translateFilterValues();
     $langcode = $filter_values['langcode'];
 
@@ -158,7 +159,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $langcode = $form_state['values']['langcode'];
     foreach ($form_state['values']['strings'] as $lid => $translations) {
       foreach ($translations['translations'] as $key => $value) {
@@ -174,7 +175,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $langcode = $form_state['values']['langcode'];
     $updated = array();
 
diff --git a/core/modules/locale/src/Form/TranslateFilterForm.php b/core/modules/locale/src/Form/TranslateFilterForm.php
index 213935a..a9be9f5 100644
--- a/core/modules/locale/src/Form/TranslateFilterForm.php
+++ b/core/modules/locale/src/Form/TranslateFilterForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\locale\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a filtered translation edit form.
  */
@@ -22,7 +24,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $filters = $this->translateFilters();
     $filter_values = $this->translateFilterValues();
 
@@ -82,7 +84,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $filters = $this->translateFilters();
     foreach ($filters as $name => $filter) {
       if (isset($form_state['values'][$name])) {
@@ -95,7 +97,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Provides a submit handler for the reset button.
    */
-  public function resetForm(array &$form, array &$form_state) {
+  public function resetForm(array &$form, FormStateInterface $form_state) {
     $_SESSION['locale_translate_filter'] = array();
     $form_state['redirect_route']['route_name'] = 'locale.translate_page';
   }
diff --git a/core/modules/locale/src/Form/TranslationStatusForm.php b/core/modules/locale/src/Form/TranslationStatusForm.php
index a1c7e34..b09658f 100644
--- a/core/modules/locale/src/Form/TranslationStatusForm.php
+++ b/core/modules/locale/src/Form/TranslationStatusForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -67,7 +68,7 @@ public function getFormID() {
    *
    * @ingroup forms
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $languages = locale_translatable_language_list();
     $status = locale_translation_get_status();
     $options = array();
@@ -264,7 +265,7 @@ protected function createInfoString($project_info) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Check if a language has been selected. 'tableselect' doesn't.
     if (!array_filter($form_state['values']['langcodes'])) {
       $this->setFormError('', $this->t('Select a language to update.'));
@@ -274,7 +275,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->moduleHandler->loadInclude('locale', 'fetch.inc');
     $langcodes = array_filter($form_state['values']['langcodes']);
     $projects = array_filter($form_state['values']['projects_update']);
diff --git a/core/modules/locale/src/Tests/LocaleLocaleLookupTest.php b/core/modules/locale/src/Tests/LocaleLocaleLookupTest.php
index b25d639..4f4c3d5 100644
--- a/core/modules/locale/src/Tests/LocaleLocaleLookupTest.php
+++ b/core/modules/locale/src/Tests/LocaleLocaleLookupTest.php
@@ -22,7 +22,7 @@ class LocaleLocaleLookupTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('locale', 'menu_link');
+  public static $modules = array('locale');
 
   /**
    * Tests hasTranslation().
diff --git a/core/modules/menu_link/menu_link.api.php b/core/modules/menu_link/menu_link.api.php
deleted file mode 100644
index 4702436..0000000
--- a/core/modules/menu_link/menu_link.api.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-/**
- * @file
- * Hooks provided by the Menu link module.
- */
-
-/**
- * @addtogroup hooks
- * @{
- */
-
-/**
- * Alter a menu link after it has been translated and before it is rendered.
- *
- * This hook is invoked from _menu_link_translate() after a menu link has been
- * translated; i.e., after the user access to the link's target page has
- * been checked. It is only invoked if $menu_link['options']['alter'] has been
- * set to a non-empty value (e.g. TRUE). This flag should be set using
- * hook_ENTITY_TYPE_presave() for entity 'menu_link'.
- *
- * Implementations of this hook are able to alter any property of the menu link.
- * For example, this hook may be used to add a page-specific query string to all
- * menu links, or hide a certain link by setting:
- * @code
- *   'hidden' => 1,
- * @endcode
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   A menu link entity.
- *
- * @see hook_menu_link_alter()
- */
-function hook_translated_menu_link_alter(\Drupal\menu_link\Entity\MenuLink &$menu_link, $map) {
-  if ($menu_link->href == 'devel/cache/clear') {
-    $menu_link->localized_options['query'] = drupal_get_destination();
-  }
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/core/modules/menu_link/menu_link.info.yml b/core/modules/menu_link/menu_link.info.yml
deleted file mode 100644
index bc8e62b..0000000
--- a/core/modules/menu_link/menu_link.info.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: Menu Link
-type: module
-description: Provides menu links.
-package: Core
-version: VERSION
-core: 8.x
-# @todo Menu links functionality has been moved from system.module and menu.inc
-# to this module, so make it required until everything is moved over.
-required: TRUE
diff --git a/core/modules/menu_link/menu_link.install b/core/modules/menu_link/menu_link.install
deleted file mode 100644
index c789d34..0000000
--- a/core/modules/menu_link/menu_link.install
+++ /dev/null
@@ -1,221 +0,0 @@
-<?php
-
-/**
- * @file
- * Install, update and uninstall functions for the menu_link module.
- */
-
-/**
- * Implements hook_schema().
- */
-function menu_link_schema() {
-  $schema['menu_links'] = array(
-    'description' => 'Contains the individual links within a menu.',
-    'fields' => array(
-     'menu_name' => array(
-        'description' => "The menu name. All links with the same menu name (such as 'tools') are part of the same menu.",
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'mlid' => array(
-        'description' => 'The menu link ID (mlid) is the integer primary key.',
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-      ),
-      'uuid' => array(
-        'description' => 'Unique Key: Universally unique identifier for this entity.',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => FALSE,
-      ),
-      'machine_name' => array(
-        'description' => 'Unique machine name: Optional human-readable ID for this link.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => FALSE,
-      ),
-      'plid' => array(
-        'description' => 'The parent link ID (plid) is the mlid of the link above in the hierarchy, or zero if the link is at the top level in its menu.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'link_path' => array(
-        'description' => 'The Drupal path or external path this link points to.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of this link.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'link_title' => array(
-        'description' => 'The text displayed for the link.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'options' => array(
-        'description' => 'A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.',
-        'type' => 'blob',
-        'not null' => FALSE,
-        'serialize' => TRUE,
-      ),
-      'module' => array(
-        'description' => 'The name of the module that generated this link.',
-        'type' => 'varchar',
-        'length' => DRUPAL_EXTENSION_NAME_MAX_LENGTH,
-        'not null' => TRUE,
-        'default' => 'system',
-      ),
-      'hidden' => array(
-        'description' => 'A flag for whether the link should be rendered in menus. (1 = a disabled menu item that may be shown on admin screens, -1 = a menu callback, 0 = a normal, visible link)',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'external' => array(
-        'description' => 'A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'has_children' => array(
-        'description' => 'Flag indicating whether any links have this link as a parent (1 = children exist, 0 = no children).',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'expanded' => array(
-        'description' => 'Flag for whether this link should be rendered as expanded in menus - expanded links always have their child links displayed, instead of only when the link is in the active trail (1 = expanded, 0 = not expanded)',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'weight' => array(
-        'description' => 'Link weight among links in the same menu at the same depth.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'depth' => array(
-        'description' => 'The depth relative to the top level. A link with plid == 0 will have depth == 1.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'customized' => array(
-        'description' => 'A flag to indicate that the user has manually created or edited the link (1 = customized, 0 = not customized).',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'p1' => array(
-        'description' => 'The first mlid in the materialized path. If N = depth, then pN must equal the mlid. If depth > 1 then p(N-1) must equal the plid. All pX where X > depth must equal zero. The columns p1 .. p9 are also called the parents.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p2' => array(
-        'description' => 'The second mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p3' => array(
-        'description' => 'The third mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p4' => array(
-        'description' => 'The fourth mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p5' => array(
-        'description' => 'The fifth mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p6' => array(
-        'description' => 'The sixth mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p7' => array(
-        'description' => 'The seventh mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p8' => array(
-        'description' => 'The eighth mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'p9' => array(
-        'description' => 'The ninth mlid in the materialized path. See p1.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'updated' => array(
-        'description' => 'Flag that indicates that this link was generated during the update from Drupal 5.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'small',
-      ),
-      'route_name' => array(
-        'description' => 'The machine name of a defined Symfony Route this menu item represents.',
-        'type' => 'varchar',
-        'length' => 255,
-      ),
-      'route_parameters' => array(
-        'description' => 'Serialized array of route parameters of this menu link.',
-        'type' => 'blob',
-        'size' => 'big',
-        'not null' => FALSE,
-        'serialize' => TRUE,
-      ),
-    ),
-    'indexes' => array(
-      'path_menu' => array(array('link_path', 128), 'menu_name'),
-      'menu_plid_expand_child' => array('menu_name', 'plid', 'expanded', 'has_children'),
-      'menu_parents' => array('menu_name', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
-    ),
-    'primary key' => array('mlid'),
-  );
-
-  return $schema;
-}
diff --git a/core/modules/menu_link/menu_link.module b/core/modules/menu_link/menu_link.module
deleted file mode 100644
index 8a2ce38..0000000
--- a/core/modules/menu_link/menu_link.module
+++ /dev/null
@@ -1,225 +0,0 @@
-<?php
-
-/**
- * @file
- * Enables users to create menu links.
- */
-
-use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\Url;
-use Drupal\menu_link\Entity\MenuLink;
-use Drupal\menu_link\MenuLinkInterface;
-
-function menu_link_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.menu_link':
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Menu Link module allows users to create menu links. It is required by the Menu UI module, which provides an interface for managing menus. See the <a href="!menu-help">Menu UI module help page</a> for more information.', array('!menu-help' => \Drupal::url('help.page', array('name' => 'menu_ui')))) . '</p>';
-      return $output;
-  }
-}
-
-/**
- * Entity URI callback.
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   A menu link entity.
- */
-function menu_link_uri(MenuLink $menu_link) {
-  return new Url($menu_link->route_name, $menu_link->route_parameters);
-}
-
-/**
- * Loads a menu link entity.
- *
- * This function should never be called from within node_load() or any other
- * function used as a menu object load function since an infinite recursion may
- * occur.
- *
- * @param int $mlid
- *   The menu link ID.
- * @param bool $reset
- *   (optional) Whether to reset the menu_link_load_multiple() cache.
- *
- * @return \Drupal\menu_link\Entity\MenuLink|null
- *   A menu link entity, or NULL if there is no entity with the given ID.
- *
- * @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
- *   Use \Drupal\menu_link\Entity\MenuLink::load().
- */
-function menu_link_load($mlid = NULL, $reset = FALSE) {
-  if ($reset) {
-    \Drupal::entityManager()->getStorage('menu_link')->resetCache(array($mlid));
-  }
-  return MenuLink::load($mlid);
-}
-
-/**
- * Loads menu link entities from the database.
- *
- * @param array $mlids
- *   (optional) An array of entity IDs. If omitted, all entities are loaded.
- * @param bool $reset
- *   (optional) Whether to reset the internal cache.
- *
- * @return array<\Drupal\menu_link\Entity\MenuLink>
- *   An array of menu link entities indexed by entity IDs.
- *
- * @see menu_link_load()
- * @see entity_load_multiple()
- *
- * @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
- *   Use \Drupal\menu_link\Entity\MenuLink::loadMultiple().
- */
-function menu_link_load_multiple(array $mlids = NULL, $reset = FALSE) {
-  if ($reset) {
-    \Drupal::entityManager()->getStorage('menu_link')->resetCache($mlids);
-  }
-  return MenuLink::loadMultiple($mlids);
-}
-
-/**
- * Deletes a menu link.
- *
- * @param int $mlid
- *   The menu link ID.
- *
- * @see menu_link_delete_multiple()
- */
-function menu_link_delete($mlid) {
-  menu_link_delete_multiple(array($mlid));
-}
-
-/**
- * Deletes multiple menu links.
- *
- * @param array $mlids
- *   An array of menu link IDs.
- * @param bool $force
- *   (optional) Forces deletion. Internal use only, setting to TRUE is
- *   discouraged. Defaults to FALSE.
- * @param bool $prevent_reparenting
- *   (optional) Disables the re-parenting logic from the deletion process.
- *   Defaults to FALSE.
- */
-function menu_link_delete_multiple(array $mlids, $force = FALSE, $prevent_reparenting = FALSE) {
-  if (!$mlids) {
-    // If no IDs or invalid IDs were passed, do nothing.
-    return;
-  }
-
-  $controller = \Drupal::entityManager()
-    ->getStorage('menu_link');
-  if (!$force) {
-    $entity_query = \Drupal::entityQuery('menu_link');
-    $group = $entity_query->orConditionGroup()
-      ->condition('module', 'system', '<>')
-      ->condition('updated', 0, '<>');
-
-    $entity_query->condition('mlid', $mlids, 'IN');
-    $entity_query->condition($group);
-
-    $result = $entity_query->execute();
-    $entities = $controller->loadMultiple($result);
-  }
-  else {
-    $entities = $controller->loadMultiple($mlids);
-  }
-  $controller->setPreventReparenting($prevent_reparenting);
-  $controller->delete($entities);
-}
-
-/**
- * Saves a menu link.
- *
- * After calling this function, rebuild the menu cache using
- * menu_cache_clear_all().
- *
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   The menu link entity to be saved.
- *
- * @return int|bool
- *   Returns SAVED_NEW or SAVED_UPDATED if the save operation succeeded, or
- *   FALSE if it failed.
- */
-function menu_link_save(MenuLink $menu_link) {
-  return $menu_link->save();
-}
-
-/**
- * Inserts, updates, enables, disables, or deletes an uncustomized menu link.
- *
- * @param string $module
- *   The name of the module that owns the link.
- * @param string $op
- *   Operation to perform: insert, update, enable, disable, or delete.
- * @param string $link_path
- *   The path this link points to.
- * @param string $link_title
- *   (optional) Title of the link to insert or new title to update the link to.
- *   Unused for delete. Defaults to NULL.
- *
- * @return integer|null
- *   The insert op returns the mlid of the new item. Others op return NULL.
- */
-function menu_link_maintain($module, $op, $link_path, $link_title = NULL) {
-  $menu_link_controller = \Drupal::entityManager()
-    ->getStorage('menu_link');
-  switch ($op) {
-    case 'insert':
-      $menu_link = entity_create('menu_link', array(
-        'link_title' => $link_title,
-        'link_path' => $link_path,
-        'module' => $module,)
-      );
-      return $menu_link->save();
-
-    case 'update':
-      $menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => $link_path, 'module' => $module, 'customized' => 0));
-      foreach ($menu_links as $menu_link) {
-        $menu_link->original = clone $menu_link;
-        if (isset($link_title)) {
-          $menu_link->link_title = $link_title;
-        }
-        $menu_link_controller->save($menu_link);
-      }
-      break;
-
-    case 'enable':
-    case 'disable':
-      $menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => $link_path, 'module' => $module, 'customized' => 0));
-      foreach ($menu_links as $menu_link) {
-        $menu_link->original = clone $menu_link;
-        $menu_link->hidden = ($op == 'disable' ? 1 : 0);
-        $menu_link->customized = 1;
-        if (isset($link_title)) {
-          $menu_link->link_title = $link_title;
-        }
-        $menu_link_controller->save($menu_link);
-      }
-      break;
-
-    case 'delete':
-      $result = \Drupal::entityQuery('menu_link')->condition('link_path', $link_path)->execute();
-      if (!empty($result)) {
-        menu_link_delete_multiple($result);
-      }
-      break;
-  }
-}
-
-/**
- * Implements hook_system_breadcrumb_alter().
- */
-function menu_link_system_breadcrumb_alter(array &$breadcrumb, RouteMatchInterface $route_match, array $context) {
-  // Custom breadcrumb behavior for editing menu links, we append a link to
-  // the menu in which the link is found.
-  if (($route_match->getRouteName() == 'menu_ui.link_edit') && $menu_link = $route_match->getParameter('menu_link')) {
-    if (($menu_link instanceof MenuLinkInterface) && !$menu_link->isNew()) {
-      // Add a link to the menu admin screen.
-      $menu = entity_load('menu', $menu_link->menu_name);
-      $breadcrumb[] = Drupal::l($menu->label(), 'menu_ui.menu_edit', array('menu' => $menu->id));
-    }
-  }
-}
diff --git a/core/modules/menu_link/menu_link.services.yml b/core/modules/menu_link/menu_link.services.yml
deleted file mode 100644
index 88f5037..0000000
--- a/core/modules/menu_link/menu_link.services.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-services:
-  menu_link.tree:
-    class: Drupal\menu_link\MenuTree
-    arguments: ['@database', '@cache.data', '@language_manager', '@request_stack', '@entity.manager', '@entity.query', '@state']
-  menu_link.static:
-    class: Drupal\menu_link\StaticMenuLinks
-    arguments: ['@module_handler']
diff --git a/core/modules/menu_link/src/Entity/MenuLink.php b/core/modules/menu_link/src/Entity/MenuLink.php
deleted file mode 100644
index e2215fd..0000000
--- a/core/modules/menu_link/src/Entity/MenuLink.php
+++ /dev/null
@@ -1,680 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\Entity\MenuLink.
- */
-
-namespace Drupal\menu_link\Entity;
-
-use Drupal\Component\Utility\NestedArray;
-use Drupal\Component\Utility\UrlHelper;
-use Drupal\Core\Cache\Cache;
-use Drupal\Core\Entity\Entity;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Url;
-use Drupal\menu_link\MenuLinkInterface;
-use Symfony\Component\Routing\Route;
-
-/**
- * Defines the menu link entity class.
- *
- * @EntityType(
- *   id = "menu_link",
- *   label = @Translation("Menu link"),
- *   controllers = {
- *     "storage" = "Drupal\menu_link\MenuLinkStorage",
- *     "access" = "Drupal\menu_link\MenuLinkAccessController",
- *     "form" = {
- *       "default" = "Drupal\menu_link\MenuLinkForm"
- *     }
- *   },
- *   admin_permission = "administer menu",
- *   static_cache = FALSE,
- *   base_table = "menu_links",
- *   uri_callback = "menu_link_uri",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "mlid",
- *     "label" = "link_title",
- *     "uuid" = "uuid",
- *     "bundle" = "bundle"
- *   },
- * )
- */
-class MenuLink extends Entity implements \ArrayAccess, MenuLinkInterface {
-
-  /**
-   * The link's menu name.
-   *
-   * @var string
-   */
-  public $menu_name = 'tools';
-
-  /**
-   * The link's bundle.
-   *
-   * @var string
-   */
-  public $bundle = 'tools';
-
-  /**
-   * The menu link ID.
-   *
-   * @var int
-   */
-  public $mlid;
-
-  /**
-   * An optional machine name if defined via the menu_link.static service.
-   *
-   * @var string
-   */
-  public $machine_name;
-
-  /**
-   * The menu link UUID.
-   *
-   * @var string
-   */
-  public $uuid;
-
-  /**
-   * The parent link ID.
-   *
-   * @var int
-   */
-  public $plid;
-
-  /**
-   * The Drupal path or external path this link points to.
-   *
-   * @var string
-   */
-  public $link_path;
-
-  /**
-   * The entity label.
-   *
-   * @var string
-   */
-  public $link_title = '';
-
-  /**
-   * A serialized array of options to be passed to the url() or l() function,
-   * such as a query string or HTML attributes.
-   *
-   * @var array
-   */
-  public $options = array();
-
-  /**
-   * The name of the module that generated this link.
-   *
-   * @var string
-   */
-  public $module = 'menu_ui';
-
-  /**
-   * A flag for whether the link should be rendered in menus.
-   *
-   * @var int
-   */
-  public $hidden = 0;
-
-  /**
-   * A flag to indicate if the link points to a full URL starting with a
-   * protocol, like http:// (1 = external, 0 = internal).
-   *
-   * @var int
-   */
-  public $external;
-
-  /**
-   * Flag indicating whether any links have this link as a parent.
-   *
-   * @var int
-   */
-  public $has_children = 0;
-
-  /**
-   * Flag for whether this link should be rendered as expanded in menus.
-   * Expanded links always have their child links displayed, instead of only
-   * when the link is in the active trail.
-   *
-   * @var int
-   */
-  public $expanded = 0;
-
-  /**
-   * Link weight among links in the same menu at the same depth.
-   *
-   * @var int
-   */
-  public $weight = 0;
-
-  /**
-   * The depth relative to the top level. A link with plid == 0 will have
-   * depth == 1.
-   *
-   * @var int
-   */
-  public $depth;
-
-  /**
-   * A flag to indicate that the user has manually created or edited the link.
-   *
-   * @var int
-   */
-  public $customized = 0;
-
-  /**
-   * The first entity ID in the materialized path.
-   *
-   * @var int
-   *
-   * @todo Investigate whether the p1, p2, .. pX properties can be moved to a
-   * single array property.
-   */
-  public $p1;
-
-  /**
-   * The second entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p2;
-
-  /**
-   * The third entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p3;
-
-  /**
-   * The fourth entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p4;
-
-  /**
-   * The fifth entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p5;
-
-  /**
-   * The sixth entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p6;
-
-  /**
-   * The seventh entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p7;
-
-  /**
-   * The eighth entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p8;
-
-  /**
-   * The ninth entity ID in the materialized path.
-   *
-   * @var int
-   */
-  public $p9;
-
-  /**
-   * The menu link modification timestamp.
-   *
-   * @var int
-   */
-  public $updated = 0;
-
-  /**
-   * The name of the route associated with this menu link, if any.
-   *
-   * @var string
-   */
-  public $route_name;
-
-  /**
-   * The parameters of the route associated with this menu link, if any.
-   *
-   * @var array
-   */
-  public $route_parameters = array();
-
-  /**
-   * The route object associated with this menu link, if any.
-   *
-   * @var \Symfony\Component\Routing\Route
-   */
-  protected $routeObject;
-
-  /**
-   * Boolean indicating whether a new revision should be created on save.
-   *
-   * @var bool
-   */
-  protected $newRevision = FALSE;
-
-  /**
-   * Indicates whether this is the default revision.
-   *
-   * @var bool
-   */
-  protected $isDefaultRevision = TRUE;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setNewRevision($value = TRUE) {
-    $this->newRevision = $value;
-  }
-  /**
-   * {@inheritdoc}
-   */
-  public function isNewRevision() {
-    return $this->newRevision || ($this->getEntityType()->hasKey('revision') && !$this->getRevisionId());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRevisionId() {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isTranslatable() {
-    // @todo Inject the entity manager and retrieve bundle info from it.
-    $bundles = entity_get_bundles($this->entityTypeId);
-    return !empty($bundles[$this->bundle()]['translatable']);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) {
-  }
-
-  /**
-   * Overrides Entity::id().
-   */
-  public function id() {
-    return $this->mlid;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function bundle() {
-    return $this->bundle;
-  }
-
-  /**
-   * Overrides Entity::createDuplicate().
-   */
-  public function createDuplicate() {
-    $duplicate = parent::createDuplicate();
-    $duplicate->plid = NULL;
-    return $duplicate;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRoute() {
-    if (!$this->route_name) {
-      return NULL;
-    }
-    if (!($this->routeObject instanceof Route)) {
-      $route_provider = \Drupal::service('router.route_provider');
-      $this->routeObject = $route_provider->getRouteByName($this->route_name);
-    }
-    return $this->routeObject;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setRouteObject(Route $route) {
-    $this->routeObject = $route;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function reset() {
-    // To reset the link to its original values, we need to retrieve its
-    // definition from the menu_link.static service. Otherwise, for example,
-    // the link's menu would not be reset, because properties like the original
-    // 'menu_name' are not stored anywhere else. Since resetting a link happens
-    // rarely and this is a one-time operation, retrieving the full set of
-    // default menu links does little harm.
-    $all_links = \Drupal::service('menu_link.static')->getLinks();
-    $original = $all_links[$this->machine_name];
-    $original['machine_name'] = $this->machine_name;
-    /** @var \Drupal\menu_link\MenuLinkStorageInterface $storage */
-    $storage = \Drupal::entityManager()->getStorage($this->entityTypeId);
-    // @todo Do not create a new entity in order to update it, see
-    //   https://drupal.org/node/2241865
-    $new_link = $storage->createFromDefaultLink($original);
-    $new_link->setOriginalId($this->id());
-    // Allow the menu to be determined by the parent
-    if (!empty($new_link['parent']) && !empty($all_links[$new_link['parent']])) {
-      // Walk up the tree to find the menu name.
-      $parent = $all_links[$new_link['parent']];
-      $existing_parent = db_select('menu_links')
-        ->fields('menu_links')
-        ->condition('machine_name', $parent['machine_name'])
-        ->execute()->fetchAssoc();
-      if ($existing_parent) {
-        /** @var \Drupal\Core\Entity\EntityInterface $existing_parent */
-        $existing_parent = $storage->create($existing_parent);
-        $new_link->menu_name = $existing_parent->menu_name;
-        $new_link->plid = $existing_parent->id();
-      }
-    }
-    // Merge existing menu link's ID and 'has_children' property.
-    foreach (array('mlid', 'has_children') as $key) {
-      $new_link->{$key} = $this->{$key};
-    }
-    $new_link->save();
-    return $new_link;
-  }
-
-  /**
-   * Implements ArrayAccess::offsetExists().
-   */
-  public function offsetExists($offset) {
-    return isset($this->{$offset});
-  }
-
-  /**
-   * Implements ArrayAccess::offsetGet().
-   */
-  public function &offsetGet($offset) {
-    return $this->{$offset};
-  }
-
-  /**
-   * Implements ArrayAccess::offsetSet().
-   */
-  public function offsetSet($offset, $value) {
-    $this->{$offset} = $value;
-  }
-
-  /**
-   * Implements ArrayAccess::offsetUnset().
-   */
-  public function offsetUnset($offset) {
-    unset($this->{$offset});
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function preDelete(EntityStorageInterface $storage, array $entities) {
-    parent::preDelete($storage, $entities);
-
-    // Nothing to do if we don't want to reparent children.
-    if ($storage->getPreventReparenting()) {
-      return;
-    }
-
-    foreach ($entities as $entity) {
-      // Children get re-attached to the item's parent.
-      if ($entity->has_children) {
-        $children = $storage->loadByProperties(array('plid' => $entity->plid));
-        foreach ($children as $child) {
-          $child->plid = $entity->plid;
-          $storage->save($child);
-        }
-      }
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function postDelete(EntityStorageInterface $storage, array $entities) {
-    parent::postDelete($storage, $entities);
-
-    // Update the has_children status of the parent.
-    foreach ($entities as $entity) {
-      if (!$storage->getPreventReparenting()) {
-        $storage->updateParentalStatus($entity);
-      }
-    }
-
-    // Also clear the menu system static caches.
-    menu_reset_static_cache();
-    _menu_update_expanded_menus();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function preSave(EntityStorageInterface $storage) {
-    parent::preSave($storage);
-
-    // This is the easiest way to handle the unique internal path '<front>',
-    // since a path marked as external does not need to match a route.
-    $this->external = (UrlHelper::isExternal($this->link_path) || $this->link_path == '<front>') ? 1 : 0;
-
-    // Try to find a parent link. If found, assign it and derive its menu.
-    $parent = $this->findParent($storage);
-    if ($parent) {
-      $this->plid = $parent->id();
-      $this->menu_name = $parent->menu_name;
-    }
-    // If no corresponding parent link was found, move the link to the top-level.
-    else {
-      $this->plid = 0;
-    }
-
-    // Directly fill parents for top-level links.
-    if ($this->plid == 0) {
-      $this->p1 = $this->id();
-      for ($i = 2; $i <= MENU_MAX_DEPTH; $i++) {
-        $parent_property = "p$i";
-        $this->{$parent_property} = 0;
-      }
-      $this->depth = 1;
-    }
-    // Otherwise, ensure that this link's depth is not beyond the maximum depth
-    // and fill parents based on the parent link.
-    else {
-      if ($this->has_children && $this->original) {
-        $limit = MENU_MAX_DEPTH - $storage->findChildrenRelativeDepth($this->original) - 1;
-      }
-      else {
-        $limit = MENU_MAX_DEPTH - 1;
-      }
-      if ($parent->depth > $limit) {
-        return FALSE;
-      }
-      $this->depth = $parent->depth + 1;
-      $this->setParents($parent);
-    }
-
-    // Need to check both plid and menu_name, since plid can be 0 in any menu.
-    if (isset($this->original) && ($this->plid != $this->original->plid || $this->menu_name != $this->original->menu_name)) {
-      $storage->moveChildren($this);
-    }
-
-    // Find the route_name.
-    if (!$this->external && !isset($this->route_name)) {
-      $url = Url::createFromPath($this->link_path);
-      $this->route_name = $url->getRouteName();
-      $this->route_parameters = $url->getRouteParameters();
-    }
-    elseif (empty($this->link_path)) {
-      $this->link_path = \Drupal::urlGenerator()->getPathFromRoute($this->route_name, $this->route_parameters);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
-    parent::postSave($storage, $update);
-
-    // Check the has_children status of the parent.
-    $storage->updateParentalStatus($this);
-
-
-    // Entity::postSave() calls Entity::invalidateTagsOnSave(), which only
-    // handles the regular cases. The MenuLink entity has two special cases.
-    $cache_tags = array();
-    // Case 1: a newly created menu link is *also* added to a menu, so we must
-    // invalidate the associated menu's cache tag.
-    if (!$update) {
-      $cache_tags = $this->getCacheTag();
-    }
-    // Case 2: a menu link may be moved from one menu to another; the original
-    // menu's cache tag must also be invalidated.
-    if (isset($this->original) && $this->menu_name != $this->original->menu_name) {
-      $cache_tags = NestedArray::mergeDeep($cache_tags, $this->original->getCacheTag());
-    }
-    Cache::invalidateTags($cache_tags);
-
-    // Also clear the menu system static caches.
-    menu_reset_static_cache();
-
-    // Track which menu items are expanded.
-    _menu_update_expanded_menus();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function postLoad(EntityStorageInterface $storage, array &$entities) {
-    parent::postLoad($storage, $entities);
-
-    $routes = array();
-    foreach ($entities as $menu_link) {
-      $menu_link->options = unserialize($menu_link->options);
-      $menu_link->route_parameters = unserialize($menu_link->route_parameters);
-
-      // By default use the menu_name as type.
-      $menu_link->bundle = $menu_link->menu_name;
-
-      // For all links that have an associated route, load the route object now
-      // and save it on the object. That way we avoid a select N+1 problem later.
-      if ($menu_link->route_name) {
-        $routes[$menu_link->id()] = $menu_link->route_name;
-      }
-    }
-
-    // Now mass-load any routes needed and associate them.
-    if ($routes) {
-      $route_objects = \Drupal::service('router.route_provider')->getRoutesByNames($routes);
-      foreach ($routes as $entity_id => $route) {
-        // Not all stored routes will be valid on load.
-        if (isset($route_objects[$route])) {
-          $entities[$entity_id]->setRouteObject($route_objects[$route]);
-        }
-      }
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setParents(MenuLinkInterface $parent) {
-    $i = 1;
-    while ($i < $this->depth) {
-      $p = 'p' . $i++;
-      $this->{$p} = $parent->{$p};
-    }
-    $p = 'p' . $i++;
-    // The parent (p1 - p9) corresponding to the depth always equals the mlid.
-    $this->{$p} = $this->id();
-    while ($i <= MENU_MAX_DEPTH) {
-      $p = 'p' . $i++;
-      $this->{$p} = 0;
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function findParent(EntityStorageInterface $storage) {
-    $parent = FALSE;
-
-    // This item is explicitly top-level, skip the rest of the parenting.
-    if (isset($this->plid) && empty($this->plid)) {
-      return $parent;
-    }
-
-    // If we have a parent link ID, try to use that.
-    $candidates = array();
-    if (isset($this->plid)) {
-      $candidates[] = $this->plid;
-    }
-
-    // Else, if we have a link hierarchy try to find a valid parent in there.
-    if (!empty($this->depth) && $this->depth > 1) {
-      for ($depth = $this->depth - 1; $depth >= 1; $depth--) {
-        $parent_property = "p$depth";
-        $candidates[] = $this->$parent_property;
-      }
-    }
-
-    foreach ($candidates as $mlid) {
-      $parent = $storage->load($mlid);
-      if ($parent) {
-        break;
-      }
-    }
-    return $parent;
-  }
-
-  /**
-   * Builds and returns the renderable array for this menu link.
-   *
-   * @return array
-   *   A renderable array representing the content of the link.
-   */
-  public function build() {
-    $build = array(
-      '#type' => 'link',
-      '#title' => $this->title,
-      '#href' => $this->href,
-      '#route_name' => $this->route_name ? $this->route_name : NULL,
-      '#route_parameters' => $this->route_parameters,
-      '#options' => !empty($this->localized_options) ? $this->localized_options : array(),
-    );
-    return $build;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheTag() {
-    return entity_load('menu', $this->menu_name)->getCacheTag();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getListCacheTags() {
-    return entity_load('menu', $this->menu_name)->getListCacheTags();
-  }
-
-}
diff --git a/core/modules/menu_link/src/MenuLinkAccessController.php b/core/modules/menu_link/src/MenuLinkAccessController.php
deleted file mode 100644
index c6e6b91..0000000
--- a/core/modules/menu_link/src/MenuLinkAccessController.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuLinkAccessController.
- */
-
-namespace Drupal\menu_link;
-
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines an access controller for the menu link entity.
- *
- * @see \Drupal\menu_link\Entity\MenuLink
- */
-class MenuLinkAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
-    $access = $account->hasPermission('administer menu');
-    if ($access) {
-      switch ($operation) {
-        case 'reset':
-          // Reset allowed for items defined via hook_menu() and customized.
-          return !empty($entity->machine_name) && $entity->customized;
-
-        case 'delete':
-          // Only items created by the Menu UI module can be deleted.
-          return $entity->module == 'menu_ui' || $entity->updated == 1;
-
-      }
-    }
-    return $access;
-  }
-
-}
diff --git a/core/modules/menu_link/src/MenuLinkForm.php b/core/modules/menu_link/src/MenuLinkForm.php
deleted file mode 100644
index f5cbca1..0000000
--- a/core/modules/menu_link/src/MenuLinkForm.php
+++ /dev/null
@@ -1,311 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuLinkForm.
- */
-
-namespace Drupal\menu_link;
-
-use Drupal\Component\Utility\UrlHelper;
-use Drupal\Core\Entity\EntityForm;
-use Drupal\Core\Language\LanguageInterface;
-use Drupal\Core\Path\AliasManagerInterface;
-use Drupal\Core\Routing\UrlGenerator;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Form controller for the node edit forms.
- */
-class MenuLinkForm extends EntityForm {
-
-  /**
-   * The menu link storage.
-   *
-   * @var \Drupal\menu_link\MenuLinkStorageInterface
-   */
-  protected $menuLinkStorage;
-
-  /**
-   * The path alias manager.
-   *
-   * @var \Drupal\Core\Path\AliasManagerInterface
-   */
-  protected $pathAliasManager;
-
-  /**
-   * The URL generator.
-   *
-   * @var \Drupal\Core\Routing\UrlGenerator
-   */
-  protected $urlGenerator;
-
-  /**
-   * Constructs a new MenuLinkForm object.
-   *
-   * @param \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage
-   *   The menu link storage.
-   * @param \Drupal\Core\Path\AliasManagerInterface $path_alias_manager
-   *   The path alias manager.
-   * @param \Drupal\Core\Routing\UrlGenerator $url_generator
-   *   The URL generator.
-   */
-  public function __construct(MenuLinkStorageInterface $menu_link_storage, AliasManagerInterface $path_alias_manager, UrlGenerator $url_generator) {
-    $this->menuLinkStorage = $menu_link_storage;
-    $this->pathAliasManager = $path_alias_manager;
-    $this->urlGenerator = $url_generator;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.manager')->getStorage('menu_link'),
-      $container->get('path.alias_manager'),
-      $container->get('url_generator')
-    );
-  }
-
-  /**
-   * Overrides EntityForm::form().
-   */
-  public function form(array $form, array &$form_state) {
-    $menu_link = $this->entity;
-    // Since menu_link_load() no longer returns a translated and access checked
-    // item, do it here instead.
-    _menu_link_translate($menu_link);
-
-    $form['link_title'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Menu link title'),
-      '#default_value' => $menu_link->link_title,
-      '#description' => t('The text to be used for this link in the menu.'),
-      '#required' => TRUE,
-    );
-    foreach (array('link_path', 'mlid', 'module', 'has_children', 'options') as $key) {
-      $form[$key] = array('#type' => 'value', '#value' => $menu_link->{$key});
-    }
-    // Any item created or edited via this interface is considered "customized".
-    $form['customized'] = array('#type' => 'value', '#value' => 1);
-
-    // We are not using url() when constructing this path because it would add
-    // $base_path.
-    $path = $menu_link->link_path;
-    if (isset($menu_link->options['query'])) {
-      $path .= '?' . $this->urlGenerator->httpBuildQuery($menu_link->options['query']);
-    }
-    if (isset($menu_link->options['fragment'])) {
-      $path .= '#' . $menu_link->options['fragment'];
-    }
-    if ($menu_link->module == 'menu_ui') {
-      $form['link_path'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Path'),
-        '#maxlength' => 255,
-        '#default_value' => $path,
-        '#description' => t('The path for this menu link. This can be an internal Drupal path such as %add-node or an external URL such as %drupal. Enter %front to link to the front page.', array('%front' => '<front>', '%add-node' => 'node/add', '%drupal' => 'http://drupal.org')),
-        '#required' => TRUE,
-      );
-    }
-    else {
-      $form['_path'] = array(
-        '#type' => 'item',
-        '#title' => t('Path'),
-        '#description' => l($menu_link->link_title, $menu_link->href, $menu_link->options),
-      );
-    }
-
-    $form['description'] = array(
-      '#type' => 'textarea',
-      '#title' => t('Description'),
-      '#default_value' => isset($menu_link->options['attributes']['title']) ? $menu_link->options['attributes']['title'] : '',
-      '#rows' => 1,
-      '#description' => t('Shown when hovering over the menu link.'),
-    );
-    $form['enabled'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Enabled'),
-      '#default_value' => !$menu_link->hidden,
-      '#description' => t('Menu links that are not enabled will not be listed in any menu.'),
-    );
-    $form['expanded'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show as expanded'),
-      '#default_value' => $menu_link->expanded,
-      '#description' => t('If selected and this menu link has children, the menu will always appear expanded.'),
-    );
-
-    // Generate a list of possible parents (not including this link or descendants).
-    $options = menu_ui_parent_options(menu_ui_get_menus(), $menu_link);
-    $default = $menu_link->menu_name . ':' . $menu_link->plid;
-    if (!isset($options[$default])) {
-      $default = 'tools:0';
-    }
-    $form['parent'] = array(
-      '#type' => 'select',
-      '#title' => t('Parent link'),
-      '#default_value' => $default,
-      '#options' => $options,
-      '#description' => t('The maximum depth for a link and all its children is fixed at !maxdepth. Some menu links may not be available as parents if selecting them would exceed this limit.', array('!maxdepth' => MENU_MAX_DEPTH)),
-      '#attributes' => array('class' => array('menu-title-select')),
-    );
-
-    // Get number of items in menu so the weight selector is sized appropriately.
-    $delta = $this->menuLinkStorage->countMenuLinks($menu_link->menu_name);
-    $form['weight'] = array(
-      '#type' => 'weight',
-      '#title' => t('Weight'),
-      // Old hardcoded value.
-      '#delta' => max($delta, 50),
-      '#default_value' => $menu_link->weight,
-      '#description' => t('Optional. In the menu, the heavier links will sink and the lighter links will be positioned nearer the top.'),
-    );
-
-    // Language module allows to configure the menu link language independently
-    // of the menu language. It also allows to optionally show the language
-    // selector on the menu link form so that the language of each menu link can
-    // be configured individually.
-    if ($this->moduleHandler->moduleExists('language')) {
-      $language_configuration = language_get_default_configuration('menu_link', $menu_link->bundle());
-      $default_langcode = ($menu_link->isNew() ? $language_configuration['langcode'] : $menu_link->langcode);
-      $language_show = $language_configuration['language_show'];
-    }
-    // Without Language module menu links inherit the menu language and no
-    // language selector is shown.
-    else {
-      $default_langcode = ($menu_link->isNew() ? entity_load('menu', $menu_link->menu_name)->language()->getId() : $menu_link->langcode);
-      $language_show = FALSE;
-    }
-
-    $form['langcode'] = array(
-      '#type' => 'language_select',
-      '#title' => t('Language'),
-      '#languages' => LanguageInterface::STATE_ALL,
-      '#default_value' => $default_langcode,
-      '#access' => $language_show,
-    );
-
-    return parent::form($form, $form_state, $menu_link);
-  }
-
-  /**
-   * Overrides EntityForm::actions().
-   */
-  protected function actions(array $form, array &$form_state) {
-    $element = parent::actions($form, $form_state);
-    $element['submit']['#button_type'] = 'primary';
-    return $element;
-  }
-
-  /**
-   * Overrides EntityForm::validate().
-   */
-  public function validate(array $form, array &$form_state) {
-    $menu_link = $this->buildEntity($form, $form_state);
-
-    $normal_path = $this->pathAliasManager->getPathByAlias($menu_link->link_path);
-    if ($menu_link->link_path != $normal_path) {
-      drupal_set_message(t('The menu system stores system paths only, but will use the URL alias for display. %link_path has been stored as %normal_path', array('%link_path' => $menu_link->link_path, '%normal_path' => $normal_path)));
-      $menu_link->link_path = $normal_path;
-      $form_state['values']['link_path'] = $normal_path;
-    }
-    if (!UrlHelper::isExternal($menu_link->link_path)) {
-      $parsed_link = parse_url($menu_link->link_path);
-      if (isset($parsed_link['query'])) {
-        $menu_link->options['query'] = array();
-        parse_str($parsed_link['query'], $menu_link->options['query']);
-      }
-      else {
-        // Use unset() rather than setting to empty string
-        // to avoid redundant serialized data being stored.
-        unset($menu_link->options['query']);
-      }
-      if (isset($parsed_link['fragment'])) {
-        $menu_link->options['fragment'] = $parsed_link['fragment'];
-      }
-      else {
-        unset($menu_link->options['fragment']);
-      }
-      if (isset($parsed_link['path']) && $menu_link->link_path != $parsed_link['path']) {
-        $menu_link->link_path = $parsed_link['path'];
-      }
-    }
-    if (!trim($menu_link->link_path) || !drupal_valid_path($menu_link->link_path, TRUE)) {
-      $this->setFormError('link_path', $form_state, $this->t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $menu_link->link_path)));
-    }
-
-    parent::validate($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildEntity(array $form, array &$form_state) {
-    // @todo: Remove this when menu links are converted to content entities in
-    //   http://drupal.org/node/1842858.
-    $entity = clone $this->entity;
-    // If you submit a form, the form state comes from caching, which forces
-    // the controller to be the one before caching. Ensure to have the
-    // controller of the current request.
-    $form_state['controller'] = $this;
-
-    // Copy top-level form values to entity properties, without changing
-    // existing entity properties that are not being edited by
-    // this form.
-    foreach ($form_state['values'] as $key => $value) {
-      $entity->$key = $value;
-    }
-
-    // Invoke all specified builders for copying form values to entity properties.
-    if (isset($form['#entity_builders'])) {
-      foreach ($form['#entity_builders'] as $function) {
-        call_user_func_array($function, array($entity->getEntityTypeId(), $entity, &$form, &$form_state));
-      }
-    }
-
-    return $entity;
-  }
-
-  /**
-   * Overrides EntityForm::submit().
-   */
-  public function submit(array $form, array &$form_state) {
-    // Build the menu link object from the submitted values.
-    $menu_link = parent::submit($form, $form_state);
-
-    // The value of "hidden" is the opposite of the value supplied by the
-    // "enabled" checkbox.
-    $menu_link->hidden = (int) !$menu_link->enabled;
-    unset($menu_link->enabled);
-
-    $menu_link->options['attributes']['title'] = $menu_link->description;
-    list($menu_link->menu_name, $menu_link->plid) = explode(':', $menu_link->parent);
-
-    return $menu_link;
-  }
-
-  /**
-   * Overrides EntityForm::save().
-   */
-  public function save(array $form, array &$form_state) {
-    $menu_link = $this->entity;
-
-    $saved = $menu_link->save();
-
-    if ($saved) {
-      drupal_set_message(t('The menu link has been saved.'));
-      $form_state['redirect_route'] = array(
-        'route_name' => 'menu_ui.menu_edit',
-        'route_parameters' => array(
-          'menu' => $menu_link->menu_name,
-        ),
-      );
-    }
-    else {
-      drupal_set_message(t('There was an error saving the menu link.'), 'error');
-      $form_state['rebuild'] = TRUE;
-    }
-  }
-
-}
diff --git a/core/modules/menu_link/src/MenuLinkInterface.php b/core/modules/menu_link/src/MenuLinkInterface.php
deleted file mode 100644
index fdfab67..0000000
--- a/core/modules/menu_link/src/MenuLinkInterface.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuLinkInterface.
- */
-
-namespace Drupal\menu_link;
-
-use Drupal\Core\Entity\EntityInterface;
-use Symfony\Component\Routing\Route;
-
-/**
- * Provides an interface defining a menu link entity.
- */
-interface MenuLinkInterface extends EntityInterface {
-
-  /**
-   * Returns the Route object associated with this link, if any.
-   *
-   * @return \Symfony\Component\Routing\Route|null
-   *   The route object for this menu link, or NULL if there isn't one.
-   */
-  public function getRoute();
-
-  /**
-   * Sets the route object for this link.
-   *
-   * This should only be called by MenuLinkStorage when loading
-   * the link object. Calling it at other times could result in unpredictable
-   * behavior.
-   *
-   * @param \Symfony\Component\Routing\Route $route
-   */
-  public function setRouteObject(Route $route);
-
-  /**
-   * Resets a system-defined menu link.
-   *
-   * @return \Drupal\menu_link\MenuLinkInterface
-   *   A menu link entity.
-   */
-  public function reset();
-
-}
diff --git a/core/modules/menu_link/src/MenuLinkStorage.php b/core/modules/menu_link/src/MenuLinkStorage.php
deleted file mode 100644
index 1ece00d..0000000
--- a/core/modules/menu_link/src/MenuLinkStorage.php
+++ /dev/null
@@ -1,319 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuLinkStorage.
- */
-
-namespace Drupal\menu_link;
-
-use Drupal\Core\Entity\EntityDatabaseStorage;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityStorageException;
-
-/**
- * Controller class for menu links.
- *
- * This extends the Drupal\entity\EntityDatabaseStorage class, adding
- * required special handling for menu_link entities.
- */
-class MenuLinkStorage extends EntityDatabaseStorage implements MenuLinkStorageInterface {
-
-  /**
-   * Indicates whether the delete operation should re-parent children items.
-   *
-   * @var bool
-   */
-  protected $preventReparenting = FALSE;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function create(array $values = array()) {
-    // The bundle of menu links being the menu name is not enforced but is the
-    // default behavior if no bundle is set.
-    if (!isset($values['bundle']) && isset($values['menu_name'])) {
-      $values['bundle'] = $values['menu_name'];
-    }
-    return parent::create($values);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save(EntityInterface $entity) {
-
-    // We return SAVED_UPDATED by default because the logic below might not
-    // update the entity if its values haven't changed, so returning FALSE
-    // would be confusing in that situation.
-    $return = SAVED_UPDATED;
-
-    $transaction = $this->database->startTransaction();
-    try {
-      // Load the stored entity, if any.
-      if (!$entity->isNew() && !isset($entity->original)) {
-        $id = $entity->id();
-        if ($entity->getOriginalId() !== NULL) {
-          $id = $entity->getOriginalId();
-        }
-        $entity->original = $this->loadUnchanged($id);
-      }
-
-      if ($entity->isNew()) {
-        $entity->mlid = $this->database->insert($this->entityType->getBaseTable())->fields(array('menu_name' => $entity->menu_name))->execute();
-        $entity->enforceIsNew();
-      }
-
-      // Unlike the save() method from EntityDatabaseStorage, we invoke the
-      // 'presave' hook first because we want to allow modules to alter the
-      // entity before all the logic from our preSave() method.
-      $this->invokeHook('presave', $entity);
-      $entity->preSave($this);
-
-      // If every value in $entity->original is the same in the $entity, there
-      // is no reason to run the update queries or clear the caches. We use
-      // array_intersect_key() with the $entity as the first parameter because
-      // $entity may have additional keys left over from building a router entry.
-      // The intersect removes the extra keys, allowing a meaningful comparison.
-      if ($entity->isNew() || (array_intersect_key(get_object_vars($entity), get_object_vars($entity->original)) != get_object_vars($entity->original))) {
-        $return = drupal_write_record($this->entityType->getBaseTable(), $entity, $this->idKey);
-
-        if ($return) {
-          if (!$entity->isNew()) {
-            $this->resetCache(array($entity->{$this->idKey}));
-            $entity->postSave($this, TRUE);
-            $this->invokeHook('update', $entity);
-          }
-          else {
-            $return = SAVED_NEW;
-            $this->resetCache();
-
-            $entity->enforceIsNew(FALSE);
-            $entity->postSave($this, FALSE);
-            $this->invokeHook('insert', $entity);
-          }
-        }
-      }
-
-      // Ignore replica server temporarily.
-      db_ignore_replica();
-      unset($entity->original);
-
-      return $return;
-    }
-    catch (\Exception $e) {
-      $transaction->rollback();
-      watchdog_exception($this->entityTypeId, $e);
-      throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPreventReparenting($value = FALSE) {
-    $this->preventReparenting = $value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPreventReparenting() {
-    return $this->preventReparenting;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function loadUpdatedCustomized(array $router_paths) {
-    $query = parent::buildQuery(NULL);
-    $query
-      ->condition(db_or()
-      ->condition('updated', 1)
-      ->condition(db_and()
-        ->condition('router_path', $router_paths, 'NOT IN')
-        ->condition('external', 0)
-        ->condition('customized', 1)
-        )
-      );
-    $query_result = $query->execute();
-
-    // We provide the necessary arguments for PDO to create objects of the
-    // specified entity class.
-    // @see \Drupal\Core\Entity\EntityInterface::__construct()
-    $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityClass, array(array(), $this->entityTypeId));
-
-    return $query_result->fetchAllAssoc($this->idKey);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function loadModuleAdminTasks() {
-    // @todo - this code will move out of the menu link entity, so we are doing
-    //   a straight SQL query for expediency.
-    $result = $this->database->select('menu_links');
-    $result->condition('machine_name', 'system.admin');
-    $result->addField('menu_links', 'mlid');
-    $plid = $result->execute()->fetchField();
-
-    $query = $this->database->select('menu_links', 'base', array('fetch' => \PDO::FETCH_ASSOC));
-    $query->fields('base');
-    $query
-      ->condition('base.hidden', 0, '>=')
-      ->condition('base.module', '', '>')
-      ->condition('base.machine_name', '', '>')
-      ->condition('base.p1', $plid);
-    $entities = $query->execute()->fetchAll();
-
-    return $entities;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function updateParentalStatus(EntityInterface $entity, $exclude = FALSE) {
-    // If plid == 0, there is nothing to update.
-    if ($entity->plid) {
-      // Check if at least one visible child exists in the table.
-      $query = $this->getQuery();
-      $query
-        ->condition('menu_name', $entity->menu_name)
-        ->condition('hidden', 0)
-        ->condition('plid', $entity->plid)
-        ->count();
-
-      if ($exclude) {
-        $query->condition('mlid', $entity->id(), '<>');
-      }
-
-      $parent_has_children = ((bool) $query->execute()) ? 1 : 0;
-      $this->database->update('menu_links')
-        ->fields(array('has_children' => $parent_has_children))
-        ->condition('mlid', $entity->plid)
-        ->execute();
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function findChildrenRelativeDepth(EntityInterface $entity) {
-    // @todo Since all we need is a specific field from the base table, does it
-    // make sense to convert to EFQ?
-    $query = $this->database->select('menu_links');
-    $query->addField('menu_links', 'depth');
-    $query->condition('menu_name', $entity->menu_name);
-    $query->orderBy('depth', 'DESC');
-    $query->range(0, 1);
-
-    $i = 1;
-    $p = 'p1';
-    while ($i <= MENU_MAX_DEPTH && $entity->{$p}) {
-      $query->condition($p, $entity->{$p});
-      $p = 'p' . ++$i;
-    }
-
-    $max_depth = $query->execute()->fetchField();
-
-    return ($max_depth > $entity->depth) ? $max_depth - $entity->depth : 0;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function moveChildren(EntityInterface $entity) {
-    $query = $this->database->update($this->entityType->getBaseTable());
-
-    $query->fields(array('menu_name' => $entity->menu_name));
-
-    $p = 'p1';
-    $expressions = array();
-    for ($i = 1; $i <= $entity->depth; $p = 'p' . ++$i) {
-      $expressions[] = array($p, ":p_$i", array(":p_$i" => $entity->{$p}));
-    }
-    $j = $entity->original->depth + 1;
-    while ($i <= MENU_MAX_DEPTH && $j <= MENU_MAX_DEPTH) {
-      $expressions[] = array('p' . $i++, 'p' . $j++, array());
-    }
-    while ($i <= MENU_MAX_DEPTH) {
-      $expressions[] = array('p' . $i++, 0, array());
-    }
-
-    $shift = $entity->depth - $entity->original->depth;
-    if ($shift > 0) {
-      // The order of expressions must be reversed so the new values don't
-      // overwrite the old ones before they can be used because "Single-table
-      // UPDATE assignments are generally evaluated from left to right"
-      // @see http://dev.mysql.com/doc/refman/5.0/en/update.html
-      $expressions = array_reverse($expressions);
-    }
-    foreach ($expressions as $expression) {
-      $query->expression($expression[0], $expression[1], $expression[2]);
-    }
-
-    $query->expression('depth', 'depth + :depth', array(':depth' => $shift));
-    $query->condition('menu_name', $entity->original->menu_name);
-    $p = 'p1';
-    for ($i = 1; $i <= MENU_MAX_DEPTH && $entity->original->{$p}; $p = 'p' . ++$i) {
-      $query->condition($p, $entity->original->{$p});
-    }
-
-    $query->execute();
-
-    // Check the has_children status of the parent, while excluding this item.
-    $this->updateParentalStatus($entity->original, TRUE);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function countMenuLinks($menu_name) {
-    $query = $this->getQuery();
-    $query
-      ->condition('menu_name', $menu_name)
-      ->count();
-    return $query->execute();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getParentFromHierarchy(EntityInterface $entity) {
-    $parent_path = $entity->link_path;
-    do {
-      $parent = FALSE;
-      $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
-
-      $query = $this->getQuery();
-      $query
-        ->condition('mlid', $entity->id(), '<>')
-        ->condition('module', 'system')
-        // We always respect the link's 'menu_name'; inheritance for router
-        // items is ensured in _menu_router_build().
-        ->condition('menu_name', $entity->menu_name)
-        ->condition('link_path', $parent_path);
-
-      $result = $query->execute();
-      // Only valid if we get a unique result.
-      if (count($result) == 1) {
-        $parent = $this->load(reset($result));
-      }
-    } while ($parent === FALSE && $parent_path);
-
-    return $parent;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createFromDefaultLink(array $item) {
-    // Suggested items are disabled by default.
-    $item += array(
-      'hidden' => 0,
-      'options' => empty($item['description']) ? array() : array('attributes' => array('title' => $item['description'])),
-    );
-    return $this->create($item);
-  }
-
-}
diff --git a/core/modules/menu_link/src/MenuLinkStorageInterface.php b/core/modules/menu_link/src/MenuLinkStorageInterface.php
deleted file mode 100644
index 3d3fd5d..0000000
--- a/core/modules/menu_link/src/MenuLinkStorageInterface.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuLinkStorageInterface.
-*/
-
-namespace Drupal\menu_link;
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-
-/**
- * Defines a common interface for menu link entity controller classes.
- */
-interface MenuLinkStorageInterface extends EntityStorageInterface {
-
-  /**
-   * Sets an internal flag that allows us to prevent the reparenting operations
-   * executed during deletion.
-   *
-   * @param bool $value
-   *   TRUE if reparenting should be allowed, FALSE if it should be prevented.
-   */
-  public function setPreventReparenting($value = FALSE);
-
-  /**
-   * Gets value of internal flag that allows/prevents reparenting operations
-   * executed during deletion.
-   *
-   * @return bool
-   *   TRUE if reparenting is allowed, FALSE if it is prevented.
-   */
-  public function getPreventReparenting();
-
-  /**
-   * Loads system menu link as needed by system_get_module_admin_tasks().
-   *
-   * @return array
-   *   An array of menu link entities indexed by their IDs.
-   */
-  public function loadModuleAdminTasks();
-
-  /**
-   * Checks and updates the 'has_children' property for the parent of a link.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   A menu link entity.
-   */
-  public function updateParentalStatus(EntityInterface $entity, $exclude = FALSE);
-
-  /**
-   * Finds the depth of an item's children relative to its depth.
-   *
-   * For example, if the item has a depth of 2 and the maximum of any child in
-   * the menu link tree is 5, the relative depth is 3.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   A menu link entity.
-   *
-   * @return int
-   *   The relative depth, or zero.
-   */
-  public function findChildrenRelativeDepth(EntityInterface $entity);
-
-  /**
-   * Updates the children of a menu link that is being moved.
-   *
-   * The menu name, parents (p1 - p6), and depth are updated for all children of
-   * the link, and the has_children status of the previous parent is updated.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   A menu link entity.
-   */
-  public function moveChildren(EntityInterface $entity);
-
-  /**
-   * Returns the number of menu links from a menu.
-   *
-   * @param string $menu_name
-   *   The unique name of a menu.
-   */
-  public function countMenuLinks($menu_name);
-
-  /**
-   * Tries to derive menu link's parent from the path hierarchy.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   A menu link entity.
-   *
-   * @return \Drupal\Core\Entity\EntityInterface|false
-   *   A menu link entity or FALSE if not valid parent was found.
-   */
-  public function getParentFromHierarchy(EntityInterface $entity);
-
-  /**
-   * Builds a menu link entity from a default item.
-   *
-   * This function should only be called for link data from
-   * the menu_link.static service.
-   *
-   * @param array $item
-   *   An item returned from the menu_link.static service.
-   *
-   * @return \Drupal\menu_link\MenuLinkInterface
-   *   A menu link entity.
-   */
-  public function createFromDefaultLink(array $item);
-
-}
diff --git a/core/modules/menu_link/src/MenuTree.php b/core/modules/menu_link/src/MenuTree.php
deleted file mode 100644
index adbf85d..0000000
--- a/core/modules/menu_link/src/MenuTree.php
+++ /dev/null
@@ -1,619 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuTree.
- */
-
-namespace Drupal\menu_link;
-
-use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\Query\QueryFactory;
-use Drupal\Core\State\StateInterface;
-use Drupal\Core\Language\LanguageManagerInterface;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\RequestStack;
-
-/**
- * Provides the default implementation of a menu tree.
- */
-class MenuTree implements MenuTreeInterface {
-
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   *   The database connection.
-   */
-  protected $database;
-
-  /**
-   * The cache backend.
-   *
-   * @var \Drupal\Core\Cache\CacheBackendInterface
-   */
-  protected $cache;
-
-  /**
-   * The language manager.
-   *
-   * @var \Drupal\Core\Language\LanguageManagerInterface
-   */
-  protected $languageManager;
-
-  /**
-   * The request stack.
-   *
-   * @var \Symfony\Component\HttpFoundation\RequestStack
-   */
-  protected $requestStack;
-
-  /**
-   * The menu link storage.
-   *
-   * @var \Drupal\menu_link\MenuLinkStorageInterface
-   */
-  protected $menuLinkStorage;
-
-  /**
-   * The entity query factory.
-   *
-   * @var \Drupal\Core\Entity\Query\QueryFactory
-   */
-  protected $queryFactory;
-
-  /**
-   * The state.
-   *
-   * @var \Drupal\Core\State\StateInterface
-   */
-  protected $state;
-
-  /**
-   * A list of active trail paths keyed by $menu_name.
-   *
-   * @var array
-   */
-  protected $trailPaths;
-
-  /**
-   * Stores the rendered menu output keyed by $menu_name.
-   *
-   * @var array
-   */
-  protected $menuOutput;
-
-  /**
-   * Stores the menu tree used by the doBuildTree method, keyed by a cache ID.
-   *
-   * This cache ID is built using the $menu_name, the current language and
-   * some parameters passed into an entity query.
-   */
-  protected $menuTree;
-
-  /**
-   * Stores the full menu tree data keyed by a cache ID.
-   *
-   * This variable distinct from static::$menuTree by having also items without
-   * access by the current user.
-   *
-   * This cache ID is built with the menu name, a passed in root link ID, the
-   * current language as well as the maximum depth.
-   *
-   * @var array
-   */
-  protected $menuFullTrees;
-
-  /**
-   * Stores the menu tree data on the current page keyed by a cache ID.
-   *
-   * This contains less information than a tree built with buildAllData.
-   *
-   * @var array
-   */
-  protected $menuPageTrees;
-
-  /**
-   * Constructs a new MenuTree.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
-   *   The cache backend.
-   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
-   *   The language manager.
-   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
-   *   The request stack.
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
-   *   The entity query factory.
-   * @param \Drupal\Core\State\StateInterface $state
-   *   The state.
-   */
-  public function __construct(Connection $database, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, RequestStack $request_stack, EntityManagerInterface $entity_manager, QueryFactory $entity_query_factory, StateInterface $state) {
-    $this->database = $database;
-    $this->cache = $cache_backend;
-    $this->languageManager = $language_manager;
-    $this->requestStack = $request_stack;
-    $this->menuLinkStorage = $entity_manager->getStorage('menu_link');
-    $this->queryFactory = $entity_query_factory;
-    $this->state = $state;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildAllData($menu_name, $link = NULL, $max_depth = NULL) {
-    $language_interface = $this->languageManager->getCurrentLanguage();
-
-    // Use $mlid as a flag for whether the data being loaded is for the whole
-    // tree.
-    $mlid = isset($link['mlid']) ? $link['mlid'] : 0;
-    // Generate a cache ID (cid) specific for this $menu_name, $link, $language,
-    // and depth.
-    $cid = 'links:' . $menu_name . ':all:' . $mlid . ':' . $language_interface->id . ':' . (int) $max_depth;
-
-    if (!isset($this->menuFullTrees[$cid])) {
-      // If the static variable doesn't have the data, check {cache_menu}.
-      $cache = $this->cache->get($cid);
-      if ($cache && $cache->data) {
-        // If the cache entry exists, it contains the parameters for
-        // menu_build_tree().
-        $tree_parameters = $cache->data;
-      }
-      // If the tree data was not in the cache, build $tree_parameters.
-      if (!isset($tree_parameters)) {
-        $tree_parameters = array(
-          'min_depth' => 1,
-          'max_depth' => $max_depth,
-        );
-        if ($mlid) {
-          // The tree is for a single item, so we need to match the values in
-          // its p columns and 0 (the top level) with the plid values of other
-          // links.
-          $parents = array(0);
-          for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
-            if (!empty($link["p$i"])) {
-              $parents[] = $link["p$i"];
-            }
-          }
-          $tree_parameters['expanded'] = $parents;
-          $tree_parameters['active_trail'] = $parents;
-          $tree_parameters['active_trail'][] = $mlid;
-        }
-
-        // Cache the tree building parameters using the page-specific cid.
-        $this->cache->set($cid, $tree_parameters, Cache::PERMANENT, array('menu' => $menu_name));
-      }
-
-      // Build the tree using the parameters; the resulting tree will be cached
-      // by $this->doBuildTree()).
-      $this->menuFullTrees[$cid] = $this->buildTree($menu_name, $tree_parameters);
-    }
-
-    return $this->menuFullTrees[$cid];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildPageData($menu_name, $max_depth = NULL, $only_active_trail = FALSE) {
-    $language_interface = $this->languageManager->getCurrentLanguage();
-
-    // Load the request corresponding to the current page.
-    $request = $this->requestStack->getCurrentRequest();
-    $system_path = NULL;
-    if ($route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME)) {
-      // @todo https://drupal.org/node/2068471 is adding support so we can tell
-      // if this is called on a 404/403 page.
-      $system_path = $request->attributes->get('_system_path');
-      $page_not_403 = 1;
-    }
-    if (isset($system_path)) {
-      if (isset($max_depth)) {
-        $max_depth = min($max_depth, MENU_MAX_DEPTH);
-      }
-      // Generate a cache ID (cid) specific for this page.
-      $cid = 'links:' . $menu_name . ':page:' . $system_path . ':' . $language_interface->id . ':' . $page_not_403 . ':' . (int) $max_depth;
-      // If we are asked for the active trail only, and $menu_name has not been
-      // built and cached for this page yet, then this likely means that it
-      // won't be built anymore, as this function is invoked from
-      // template_preprocess_page(). So in order to not build a giant menu tree
-      // that needs to be checked for access on all levels, we simply check
-      // whether we have the menu already in cache, or otherwise, build a
-      // minimum tree containing the active trail only.
-      if (!isset($this->menuPageTrees[$cid]) && $only_active_trail) {
-        $cid .= ':trail';
-      }
-
-      if (!isset($this->menuPageTrees[$cid])) {
-        // If the static variable doesn't have the data, check {cache_menu}.
-        $cache = $this->cache->get($cid);
-        if ($cache && $cache->data) {
-          // If the cache entry exists, it contains the parameters for
-          // menu_build_tree().
-          $tree_parameters = $cache->data;
-        }
-        // If the tree data was not in the cache, build $tree_parameters.
-        if (!isset($tree_parameters)) {
-          $tree_parameters = array(
-            'min_depth' => 1,
-            'max_depth' => $max_depth,
-          );
-          $active_trail = $this->getActiveTrailIds($menu_name);
-
-          // If this page is accessible to the current user, build the tree
-          // parameters accordingly.
-          if ($page_not_403) {
-            // The active trail contains more than only array(0 => 0).
-            if (count($active_trail) > 1) {
-              // If we are asked to build links for the active trail only,skip
-              // the entire 'expanded' handling.
-              if ($only_active_trail) {
-                $tree_parameters['only_active_trail'] = TRUE;
-              }
-            }
-            $parents = $active_trail;
-
-            $expanded = $this->state->get('menu_expanded');
-            // Check whether the current menu has any links set to be expanded.
-            if (!$only_active_trail && $expanded && in_array($menu_name, $expanded)) {
-              // Collect all the links set to be expanded, and then add all of
-              // their children to the list as well.
-              do {
-                $query = $this->queryFactory->get('menu_link')
-                  ->condition('menu_name', $menu_name)
-                  ->condition('expanded', 1)
-                  ->condition('has_children', 1)
-                  ->condition('plid', $parents, 'IN')
-                  ->condition('mlid', $parents, 'NOT IN');
-                $result = $query->execute();
-                $parents += $result;
-              } while (!empty($result));
-            }
-            $tree_parameters['expanded'] = $parents;
-            $tree_parameters['active_trail'] = $active_trail;
-          }
-          // If access is denied, we only show top-level links in menus.
-          else {
-            $tree_parameters['expanded'] = $active_trail;
-            $tree_parameters['active_trail'] = $active_trail;
-          }
-          // Cache the tree building parameters using the page-specific cid.
-          $this->cache->set($cid, $tree_parameters, Cache::PERMANENT, array('menu' => $menu_name));
-        }
-
-        // Build the tree using the parameters; the resulting tree will be
-        // cached by $tihs->buildTree().
-        $this->menuPageTrees[$cid] = $this->buildTree($menu_name, $tree_parameters);
-      }
-      return $this->menuPageTrees[$cid];
-    }
-
-    return array();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getActiveTrailIds($menu_name) {
-    // Parent mlids; used both as key and value to ensure uniqueness.
-    // We always want all the top-level links with plid == 0.
-    $active_trail = array(0 => 0);
-
-    $request = $this->requestStack->getCurrentRequest();
-
-    if ($route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME)) {
-      // @todo https://drupal.org/node/2068471 is adding support so we can tell
-      // if this is called on a 404/403 page.
-      // Check if the active trail has been overridden for this menu tree.
-      $active_path = $this->getPath($menu_name);
-      // Find a menu link corresponding to the current path. If
-      // $active_path is NULL, let menu_link_get_preferred() determine
-      // the path.
-      if ($active_link = $this->menuLinkGetPreferred($menu_name, $active_path)) {
-        if ($active_link['menu_name'] == $menu_name) {
-          // Use all the coordinates, except the last one because
-          // there can be no child beyond the last column.
-          for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
-            if ($active_link['p' . $i]) {
-              $active_trail[$active_link['p' . $i]] = $active_link['p' . $i];
-            }
-          }
-        }
-      }
-    }
-    return $active_trail;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPath($menu_name, $path = NULL) {
-    if (isset($path)) {
-      $this->trailPaths[$menu_name] = $path;
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPath($menu_name) {
-    return isset($this->trailPaths[$menu_name]) ? $this->trailPaths[$menu_name] : NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function renderMenu($menu_name) {
-
-    if (!isset($this->menuOutput[$menu_name])) {
-      $tree = $this->buildPageData($menu_name);
-      $this->menuOutput[$menu_name] = $this->renderTree($tree);
-    }
-    return $this->menuOutput[$menu_name];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function renderTree($tree) {
-    $build = array();
-    $items = array();
-    $menu_name = $tree ? end($tree)['link']['menu_name'] : '';
-
-    // Pull out just the menu links we are going to render so that we
-    // get an accurate count for the first/last classes.
-    foreach ($tree as $data) {
-      if ($data['link']['access'] && !$data['link']['hidden']) {
-        $items[] = $data;
-      }
-    }
-
-    foreach ($items as $data) {
-      $class = array();
-      // Set a class for the <li>-tag. Since $data['below'] may contain local
-      // tasks, only set 'expanded' class if the link also has children within
-      // the current menu.
-      if ($data['link']['has_children'] && $data['below']) {
-        $class[] = 'expanded';
-      }
-      elseif ($data['link']['has_children']) {
-        $class[] = 'collapsed';
-      }
-      else {
-        $class[] = 'leaf';
-      }
-      // Set a class if the link is in the active trail.
-      if ($data['link']['in_active_trail']) {
-        $class[] = 'active-trail';
-        $data['link']['localized_options']['attributes']['class'][] = 'active-trail';
-      }
-
-      // Allow menu-specific theme overrides.
-      $element['#theme'] = 'menu_link__' . strtr($data['link']['menu_name'], '-', '_');
-      $element['#attributes']['class'] = $class;
-      $element['#title'] = $data['link']['title'];
-      // @todo Use route name and parameters to generate the link path, unless
-      //    it is external.
-      $element['#href'] = $data['link']['link_path'];
-      $element['#localized_options'] = !empty($data['link']['localized_options']) ? $data['link']['localized_options'] : array();
-      $element['#below'] = $data['below'] ? $this->renderTree($data['below']) : $data['below'];
-      $element['#original_link'] = $data['link'];
-      // Index using the link's unique mlid.
-      $build[$data['link']['mlid']] = $element;
-    }
-    if ($build) {
-      // Make sure drupal_render() does not re-order the links.
-      $build['#sorted'] = TRUE;
-      // Add the theme wrapper for outer markup.
-      // Allow menu-specific theme overrides.
-      $build['#theme_wrappers'][] = 'menu_tree__' . strtr($menu_name, '-', '_');
-      // Set cache tag.
-      $menu_name = $data['link']['menu_name'];
-      $build['#cache']['tags']['menu'][$menu_name] = $menu_name;
-    }
-
-    return $build;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildTree($menu_name, array $parameters = array()) {
-    // Build the menu tree.
-    $tree = $this->doBuildTree($menu_name, $parameters);
-    // Check access for the current user to each item in the tree.
-    $this->checkAccess($tree);
-    return $tree;
-  }
-
-  /**
-   * Builds a menu tree.
-   *
-   * This function may be used build the data for a menu tree only, for example
-   * to further massage the data manually before further processing happens.
-   * MenuTree::checkAccess() needs to be invoked afterwards.
-   *
-   * @param string $menu_name
-   *   The name of the menu.
-   * @param array $parameters
-   *   The parameters passed into static::buildTree()
-   *
-   * @see static::buildTree()
-   */
-  protected function doBuildTree($menu_name, array $parameters = array()) {
-    $language_interface = $this->languageManager->getCurrentLanguage();
-
-    // Build the cache id; sort parents to prevent duplicate storage and remove
-    // default parameter values.
-    if (isset($parameters['expanded'])) {
-      sort($parameters['expanded']);
-    }
-    $tree_cid = 'links:' . $menu_name . ':tree-data:' . $language_interface->id . ':' . hash('sha256', serialize($parameters));
-
-    // If we do not have this tree in the static cache, check {cache_menu}.
-    if (!isset($this->menuTree[$tree_cid])) {
-      $cache = $this->cache->get($tree_cid);
-      if ($cache && $cache->data) {
-        $this->menuTree[$tree_cid] = $cache->data;
-      }
-    }
-
-    if (!isset($this->menuTree[$tree_cid])) {
-      $query = $this->queryFactory->get('menu_link');
-      for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
-        $query->sort('p' . $i, 'ASC');
-      }
-      $query->condition('menu_name', $menu_name);
-      if (!empty($parameters['expanded'])) {
-        $query->condition('plid', $parameters['expanded'], 'IN');
-      }
-      elseif (!empty($parameters['only_active_trail'])) {
-        $query->condition('mlid', $parameters['active_trail'], 'IN');
-      }
-      $min_depth = (isset($parameters['min_depth']) ? $parameters['min_depth'] : 1);
-      if ($min_depth != 1) {
-        $query->condition('depth', $min_depth, '>=');
-      }
-      if (isset($parameters['max_depth'])) {
-        $query->condition('depth', $parameters['max_depth'], '<=');
-      }
-      // Add custom query conditions, if any were passed.
-      if (isset($parameters['conditions'])) {
-        foreach ($parameters['conditions'] as $column => $value) {
-          $query->condition($column, $value);
-        }
-      }
-
-      // Build an ordered array of links using the query result object.
-      $links = array();
-      if ($result = $query->execute()) {
-        $links = $this->menuLinkStorage->loadMultiple($result);
-      }
-      $active_trail = (isset($parameters['active_trail']) ? $parameters['active_trail'] : array());
-      $tree = $this->doBuildTreeData($links, $active_trail, $min_depth);
-
-      // Cache the data, if it is not already in the cache.
-      $this->cache->set($tree_cid, $tree, Cache::PERMANENT, array('menu' => $menu_name));
-      $this->menuTree[$tree_cid] = $tree;
-    }
-
-    return $this->menuTree[$tree_cid];
-  }
-
-  /**
-   * Sorts the menu tree and recursively checks access for each item.
-   *
-   * @param array $tree
-   *   The menu tree you wish to operate on.
-   */
-  protected function checkAccess(&$tree) {
-    $new_tree = array();
-    foreach ($tree as $key => $v) {
-      $item = &$tree[$key]['link'];
-      $this->menuLinkTranslate($item);
-      if ($item['access'] || ($item['in_active_trail'] && strpos($item['href'], '%') !== FALSE)) {
-        if ($tree[$key]['below']) {
-          $this->checkAccess($tree[$key]['below']);
-        }
-        // The weights are made a uniform 5 digits by adding 50000 as an offset.
-        // After _menu_link_translate(), $item['title'] has the localized link
-        // title. Adding the mlid to the end of the index insures that it is
-        // unique.
-        $new_tree[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $tree[$key];
-      }
-    }
-    // Sort siblings in the tree based on the weights and localized titles.
-    ksort($new_tree);
-    $tree = $new_tree;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildTreeData(array $links, array $parents = array(), $depth = 1) {
-    $tree = $this->doBuildTreeData($links, $parents, $depth);
-    $this->checkAccess($tree);
-    return $tree;
-  }
-
-  /**
-   * Prepares the data for calling $this->treeDataRecursive().
-   */
-  protected function doBuildTreeData(array $links, array $parents = array(), $depth = 1) {
-    // Reverse the array so we can use the more efficient array_pop() function.
-    $links = array_reverse($links);
-    return $this->treeDataRecursive($links, $parents, $depth);
-  }
-
-  /**
-   * Builds the data representing a menu tree.
-   *
-   * The function is a bit complex because the rendering of a link depends on
-   * the next menu link.
-   *
-   * @param array $links
-   *   A flat array of menu links that are part of the menu. Each array element
-   *   is an associative array of information about the menu link, containing
-   *   the fields from the {menu_links} table, and optionally additional
-   *   information from the {menu_router} table, if the menu item appears in
-   *   both tables. This array must be ordered depth-first.
-   *   See _menu_build_tree() for a sample query.
-   * @param array $parents
-   *   An array of the menu link ID values that are in the path from the current
-   *   page to the root of the menu tree.
-   * @param int $depth
-   *   The minimum depth to include in the returned menu tree.
-   *
-   * @return array
-   */
-  protected function treeDataRecursive(&$links, $parents, $depth) {
-    $tree = array();
-    while ($item = array_pop($links)) {
-      // We need to determine if we're on the path to root so we can later build
-      // the correct active trail.
-      $item['in_active_trail'] = in_array($item['mlid'], $parents);
-      // Add the current link to the tree.
-      $tree[$item['mlid']] = array(
-        'link' => $item,
-        'below' => array(),
-      );
-      // Look ahead to the next link, but leave it on the array so it's
-      // available to other recursive function calls if we return or build a
-      // sub-tree.
-      $next = end($links);
-      // Check whether the next link is the first in a new sub-tree.
-      if ($next && $next['depth'] > $depth) {
-        // Recursively call doBuildTreeData to build the sub-tree.
-        $tree[$item['mlid']]['below'] = $this->treeDataRecursive($links, $parents, $next['depth']);
-        // Fetch next link after filling the sub-tree.
-        $next = end($links);
-      }
-      // Determine if we should exit the loop and return.
-      if (!$next || $next['depth'] < $depth) {
-        break;
-      }
-    }
-    return $tree;
-  }
-
-  /**
-   * Wraps menu_link_get_preferred().
-   */
-  protected function menuLinkGetPreferred($menu_name, $active_path) {
-    return menu_link_get_preferred($active_path, $menu_name);
-  }
-
-  /**
-   * Wraps _menu_link_translate().
-   */
-  protected function menuLinkTranslate(&$item) {
-    _menu_link_translate($item);
-  }
-
-}
diff --git a/core/modules/menu_link/src/MenuTreeInterface.php b/core/modules/menu_link/src/MenuTreeInterface.php
deleted file mode 100644
index 418f602..0000000
--- a/core/modules/menu_link/src/MenuTreeInterface.php
+++ /dev/null
@@ -1,182 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\MenuTreeInterface.
- */
-
-namespace Drupal\menu_link;
-
-/**
- * Defines an interface for trees out of menu links.
- */
-interface MenuTreeInterface {
-
-  /**
-   * Returns a rendered menu tree.
-   *
-   * The menu item's LI element is given one of the following classes:
-   * - expanded: The menu item is showing its submenu.
-   * - collapsed: The menu item has a submenu which is not shown.
-   * - leaf: The menu item has no submenu.
-   *
-   * @param array $tree
-   *   A data structure representing the tree as returned from menu_tree_data.
-   *
-   * @return array
-   *   A structured array to be rendered by drupal_render().
-   */
-  public function renderTree($tree);
-
-  /**
-   * Sets the path for determining the active trail of the specified menu tree.
-   *
-   * This path will also affect the breadcrumbs under some circumstances.
-   * Breadcrumbs are built using the preferred link returned by
-   * menu_link_get_preferred(). If the preferred link is inside one of the menus
-   * specified in calls to static::setPath(), the preferred link will be
-   * overridden by the corresponding path returned by static::getPath().
-   *
-   * @param string $menu_name
-   *   The name of the affected menu tree.
-   * @param string $path
-   *   The path to use when finding the active trail.
-   */
-  public function setPath($menu_name, $path = NULL);
-
-  /**
-   * Gets the path for determining the active trail of the specified menu tree.
-   *
-   * @param string $menu_name
-   *   The menu name of the requested tree.
-   *
-   * @return string
-   *   A string containing the path. If no path has been specified with
-   *   static::setPath(), NULL is returned.
-   */
-  public function getPath($menu_name);
-
-  /**
-   * Gets the active trail IDs of the specified menu tree.
-   *
-   * @param string $menu_name
-   *   The menu name of the requested tree.
-   *
-   * @return array
-   *   An array containing the active trail: a list of mlids.
-   */
-  public function getActiveTrailIds($menu_name);
-
-  /**
-   * Sorts and returns the built data representing a menu tree.
-   *
-   * @param array $links
-   *   A flat array of menu links that are part of the menu. Each array element
-   *   is an associative array of information about the menu link, containing
-   *   the fields from the {menu_links} table, and optionally additional
-   *   information from the {menu_router} table, if the menu item appears in
-   *   both tables. This array must be ordered depth-first.
-   *   See _menu_build_tree() for a sample query.
-   * @param array $parents
-   *   An array of the menu link ID values that are in the path from the current
-   *   page to the root of the menu tree.
-   * @param int $depth
-   *   The minimum depth to include in the returned menu tree.
-   *
-   * @return array
-   *   An array of menu links in the form of a tree. Each item in the tree is an
-   *   associative array containing:
-   *   - link: The menu link item from $links, with additional element
-   *     'in_active_trail' (TRUE if the link ID was in $parents).
-   *   - below: An array containing the sub-tree of this item, where each
-   *     element is a tree item array with 'link' and 'below' elements. This
-   *     array will be empty if the menu item has no items in its sub-tree
-   *     having a depth greater than or equal to $depth.
-   */
-  public function buildTreeData(array $links, array $parents = array(), $depth = 1);
-
-  /**
-   * Gets the data structure for a named menu tree, based on the current page.
-   *
-   * The tree order is maintained by storing each parent in an individual
-   * field, see http://drupal.org/node/141866 for more.
-   *
-   * @param string $menu_name
-   *   The named menu links to return.
-   * @param int $max_depth
-   *   (optional) The maximum depth of links to retrieve.
-   * @param bool $only_active_trail
-   *   (optional) Whether to only return the links in the active trail (TRUE)
-   *   instead of all links on every level of the menu link tree (FALSE).
-   *   Defaults to FALSE.
-   *
-   * @return array
-   *   An array of menu links, in the order they should be rendered. The array
-   *   is a list of associative arrays -- these have two keys, link and below.
-   *   link is a menu item, ready for theming as a link. Below represents the
-   *   submenu below the link if there is one, and it is a subtree that has the
-   *   same structure described for the top-level array.
-   */
-  public function buildPageData($menu_name, $max_depth = NULL, $only_active_trail = FALSE);
-
-  /**
-   * Gets the data structure representing a named menu tree.
-   *
-   * Since this can be the full tree including hidden items, the data returned
-   * may be used for generating an an admin interface or a select.
-   *
-   * @param string $menu_name
-   *   The named menu links to return
-   * @param array $link
-   *   A fully loaded menu link, or NULL. If a link is supplied, only the
-   *   path to root will be included in the returned tree - as if this link
-   *   represented the current page in a visible menu.
-   * @param int $max_depth
-   *   Optional maximum depth of links to retrieve. Typically useful if only one
-   *   or two levels of a sub tree are needed in conjunction with a non-NULL
-   *   $link, in which case $max_depth should be greater than $link['depth'].
-   *
-   * @return array
-   *   An tree of menu links in an array, in the order they should be rendered.
-   */
-  public function buildAllData($menu_name, $link = NULL, $max_depth = NULL);
-
-  /**
-   * Renders a menu tree based on the current path.
-   *
-   * @param string $menu_name
-   *   The name of the menu.
-   *
-   * @return array
-   *   A structured array representing the specified menu on the current page,
-   *   to be rendered by drupal_render().
-   */
-  public function renderMenu($menu_name);
-
-  /**
-   * Builds a menu tree, translates links, and checks access.
-   *
-   * @param string $menu_name
-   *   The name of the menu.
-   * @param array $parameters
-   *   (optional) An associative array of build parameters. Possible keys:
-   *   - expanded: An array of parent link ids to return only menu links that
-   *     are children of one of the plids in this list. If empty, the whole menu
-   *     tree is built, unless 'only_active_trail' is TRUE.
-   *   - active_trail: An array of mlids, representing the coordinates of the
-   *     currently active menu link.
-   *   - only_active_trail: Whether to only return links that are in the active
-   *     trail. This option is ignored, if 'expanded' is non-empty.
-   *   - min_depth: The minimum depth of menu links in the resulting tree.
-   *     Defaults to 1, which is the default to build a whole tree for a menu
-   *     (excluding menu container itself).
-   *   - max_depth: The maximum depth of menu links in the resulting tree.
-   *   - conditions: An associative array of custom database select query
-   *     condition key/value pairs; see _menu_build_tree() for the actual query.
-   *
-   * @return array
-   *   A fully built menu tree.
-   */
-  public function buildTree($menu_name, array $parameters = array());
-
-}
diff --git a/core/modules/menu_link/src/StaticMenuLinks.php b/core/modules/menu_link/src/StaticMenuLinks.php
deleted file mode 100644
index d42c5ff..0000000
--- a/core/modules/menu_link/src/StaticMenuLinks.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Menu\StaticMenuLinks.
- */
-
-namespace Drupal\menu_link;
-
-use Drupal\Component\Discovery\YamlDiscovery;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-
-/**
- * Provides a service which finds and alters default menu links in yml files.
- */
-class StaticMenuLinks {
-
-  /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * Constructs a new StaticMenuLinks.
-   *
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
-   */
-  public function __construct(ModuleHandlerInterface $module_handler) {
-    $this->moduleHandler = $module_handler;
-  }
-
-  /**
-   * Gets the menu links defined in YAML files.
-   *
-   * @return array
-   *   An array of default menu links.
-   */
-  public function getLinks() {
-    $discovery = $this->getDiscovery();
-    foreach ($discovery->findAll() as $module => $menu_links) {
-      foreach ($menu_links as $machine_name => $menu_link) {
-        $all_links[$machine_name] = $menu_link;
-        $all_links[$machine_name]['machine_name'] = $machine_name;
-        $all_links[$machine_name]['module'] = $module;
-      }
-    }
-
-    $this->moduleHandler->alter('menu_link_defaults', $all_links);
-    foreach ($all_links as $machine_name => $menu_link) {
-      // Set the machine_name to the menu links added dynamically.
-      if (!isset($menu_link['machine_name'])) {
-        $all_links[$machine_name]['machine_name'] = $machine_name;
-      }
-      // Change the key to match the DB column for now.
-      $all_links[$machine_name]['link_title'] = $all_links[$machine_name]['title'];
-      unset($all_links[$machine_name]['title']);
-    }
-
-    return $all_links;
-  }
-
-  /**
-   * Creates a YAML discovery for menu links.
-   *
-   * @return \Drupal\Component\Discovery\YamlDiscovery
-   *   An YAML discovery instance.
-   */
-  protected function getDiscovery() {
-    return new YamlDiscovery('links.menu', $this->moduleHandler->getModuleDirectories());
-  }
-
-}
-
diff --git a/core/modules/menu_link/tests/src/MenuTreeTest.php b/core/modules/menu_link/tests/src/MenuTreeTest.php
deleted file mode 100644
index 747335a..0000000
--- a/core/modules/menu_link/tests/src/MenuTreeTest.php
+++ /dev/null
@@ -1,539 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_link\Tests\MenuTreeTest.
- */
-
-namespace Drupal\menu_link\Tests {
-
-use Drupal\Core\Cache\Cache;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Language\Language;
-use Drupal\menu_link\MenuTree;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\RequestStack;
-
-if (!defined('MENU_MAX_DEPTH')) {
-  define('MENU_MAX_DEPTH', 9);
-}
-
-/**
- * @coversDefaultClass \Drupal\menu_link\MenuTree
- * @group menu_link
- */
-class MenuTreeTest extends UnitTestCase {
-
-  /**
-   * The tested menu tree.
-   *
-   * @var \Drupal\menu_link\MenuTree|\Drupal\menu_link\Tests\TestMenuTree
-   */
-  protected $menuTree;
-
-  /**
-   * The mocked database connection.
-   *
-   * @var \Drupal\Core\DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $connection;
-
-  /**
-   * The mocked cache backend.
-   *
-   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $cacheBackend;
-
-  /**
-   * The mocked language manager.
-   *
-   * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $languageManager;
-
-  /**
-   * The test request stack.
-   *
-   * @var \Symfony\Component\HttpFoundation\RequestStack.
-   */
-  protected $requestStack;
-
-  /**
-   * The mocked entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $entityManager;
-
-  /**
-   * The mocked entity query factor.y
-   *
-   * @var  \Drupal\Core\Entity\Query\QueryFactory|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $entityQueryFactory;
-
-  /**
-   * The mocked state.
-   *
-   * @var \Drupal\Core\State\StateInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $state;
-
-  /**
-   * Stores some default values for a menu link.
-   *
-   * @var array
-   */
-  protected $defaultMenuLink = array(
-    'menu_name' => 'main-menu',
-    'mlid' => 1,
-    'title' => 'Example 1',
-    'route_name' => 'example1',
-    'link_path' => 'example1',
-    'access' => 1,
-    'hidden' => FALSE,
-    'has_children' => FALSE,
-    'in_active_trail' => TRUE,
-    'localized_options' => array('attributes' => array('title' => '')),
-    'weight' => 0,
-  );
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    $this->connection = $this->getMockBuilder('Drupal\Core\Database\Connection')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
-    $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
-    $this->requestStack = new RequestStack();
-    $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
-    $this->entityQueryFactory = $this->getMockBuilder('Drupal\Core\Entity\Query\QueryFactory')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $this->state = $this->getMock('Drupal\Core\State\StateInterface');
-
-    $this->menuTree = new TestMenuTree($this->connection, $this->cacheBackend, $this->languageManager, $this->requestStack, $this->entityManager, $this->entityQueryFactory, $this->state);
-  }
-
-  /**
-   * Tests active paths.
-   *
-   * @covers ::setPath
-   * @covers ::getPath
-   */
-  public function testActivePaths() {
-    $this->assertNull($this->menuTree->getPath('test_menu1'));
-
-    $this->menuTree->setPath('test_menu1', 'example_path1');
-    $this->assertEquals('example_path1', $this->menuTree->getPath('test_menu1'));
-    $this->assertNull($this->menuTree->getPath('test_menu2'));
-
-    $this->menuTree->setPath('test_menu2', 'example_path2');
-    $this->assertEquals('example_path1', $this->menuTree->getPath('test_menu1'));
-    $this->assertEquals('example_path2', $this->menuTree->getPath('test_menu2'));
-  }
-
-  /**
-   * Tests buildTreeData with a single level.
-   *
-   * @covers ::buildTreeData
-   * @covers ::doBuildTreeData
-   */
-  public function testBuildTreeDataWithSingleLevel() {
-    $items = array();
-    $items[] = array(
-      'mlid' => 1,
-      'depth' => 1,
-      'weight' => 0,
-      'title' => '',
-      'route_name' => 'example1',
-      'access' => TRUE,
-    );
-    $items[] = array(
-      'mlid' => 2,
-      'depth' => 1,
-      'weight' => 0,
-      'title' => '',
-      'route_name' => 'example2',
-      'access' => TRUE,
-    );
-
-    $result = $this->menuTree->buildTreeData($items, array(), 1);
-
-    $this->assertCount(2, $result);
-    $result1 = array_shift($result);
-    $this->assertEquals($items[0] + array('in_active_trail' => FALSE), $result1['link']);
-    $result2 = array_shift($result);
-    $this->assertEquals($items[1] + array('in_active_trail' => FALSE), $result2['link']);
-  }
-
-  /**
-   * Tests buildTreeData with a single level and one item being active.
-   *
-   * @covers ::buildTreeData
-   * @covers ::doBuildTreeData
-   */
-  public function testBuildTreeDataWithSingleLevelAndActiveItem() {
-    $items = array();
-    $items[] = array(
-      'mlid' => 1,
-      'depth' => 1,
-      'weight' => 0,
-      'title' => '',
-      'route_name' => 'example1',
-      'access' => TRUE,
-    );
-    $items[] = array(
-      'mlid' => 2,
-      'depth' => 1,
-      'weight' => 0,
-      'title' => '',
-      'route_name' => 'example2',
-      'access' => TRUE,
-    );
-
-    $result = $this->menuTree->buildTreeData($items, array(1), 1);
-
-    $this->assertCount(2, $result);
-    $result1 = array_shift($result);
-    $this->assertEquals($items[0] + array('in_active_trail' => TRUE), $result1['link']);
-    $result2 = array_shift($result);
-    $this->assertEquals($items[1] + array('in_active_trail' => FALSE), $result2['link']);
-  }
-
-  /**
-   * Tests buildTreeData with a single level and none item being active.
-   *
-   * @covers ::buildTreeData
-   * @covers ::doBuildTreeData
-   */
-  public function testBuildTreeDataWithSingleLevelAndNoActiveItem() {
-    $items = array();
-    $items[] = array(
-      'mlid' => 1,
-      'depth' => 1,
-      'weight' => 0,
-      'title' => '',
-      'route_name' => 'example1',
-      'access' => TRUE,
-    );
-    $items[] = array(
-      'mlid' => 2,
-      'depth' => 1,
-      'weight' => 0,
-      'title' => '',
-      'route_name' => 'example2',
-      'access' => TRUE,
-    );
-
-    $result = $this->menuTree->buildTreeData($items, array(3), 1);
-
-    $this->assertCount(2, $result);
-    $result1 = array_shift($result);
-    $this->assertEquals($items[0] + array('in_active_trail' => FALSE), $result1['link']);
-    $result2 = array_shift($result);
-    $this->assertEquals($items[1] + array('in_active_trail' => FALSE), $result2['link']);
-  }
-
-  /**
-   * Tests buildTreeData with a more complex example.
-   *
-   * @covers ::buildTreeData
-   * @covers ::doBuildTreeData
-   */
-  public function testBuildTreeWithComplexData() {
-    $items = array(
-      1 => array('mlid' => 1, 'depth' => 1, 'route_name' => 'example1', 'access' => TRUE, 'weight' => 0, 'title' => ''),
-      2 => array('mlid' => 2, 'depth' => 1, 'route_name' => 'example2', 'access' => TRUE, 'weight' => 0, 'title' => ''),
-      3 => array('mlid' => 3, 'depth' => 2, 'route_name' => 'example3', 'access' => TRUE, 'weight' => 0, 'title' => ''),
-      4 => array('mlid' => 4, 'depth' => 3, 'route_name' => 'example4', 'access' => TRUE, 'weight' => 0, 'title' => ''),
-      5 => array('mlid' => 5, 'depth' => 1, 'route_name' => 'example5', 'access' => TRUE, 'weight' => 0, 'title' => ''),
-    );
-
-    $tree = $this->menuTree->buildTreeData($items);
-
-    // Validate that parent items #1, #2, and #5 exist on the root level.
-    $this->assertEquals($items[1]['mlid'], $tree['50000  1']['link']['mlid']);
-    $this->assertEquals($items[2]['mlid'], $tree['50000  2']['link']['mlid']);
-    $this->assertEquals($items[5]['mlid'], $tree['50000  5']['link']['mlid']);
-
-    // Validate that child item #4 exists at the correct location in the hierarchy.
-    $this->assertEquals($items[4]['mlid'], $tree['50000  2']['below']['50000  3']['below']['50000  4']['link']['mlid']);
-  }
-
-  /**
-   * Tests getActiveTrailIds().
-   *
-   * @covers ::getActiveTrailIds()
-   */
-  public function testGetActiveTrailIds() {
-    $menu_link = array(
-      'mlid' => 10,
-      'route_name' => 'example1',
-      'p1' => 3,
-      'p2' => 2,
-      'p3' => 1,
-      'p4' => 4,
-      'p5' => 9,
-      'p6' => 5,
-      'p7' => 6,
-      'p8' => 7,
-      'p9' => 8,
-      'menu_name' => 'test_menu'
-    );
-    $this->menuTree->setPreferredMenuLink('test_menu', 'test/path', $menu_link);
-    $request = (new Request());
-    $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'test_route');
-    $this->requestStack->push($request);
-    $this->menuTree->setPath('test_menu', 'test/path');
-
-    $trail = $this->menuTree->getActiveTrailIds('test_menu');
-    $this->assertEquals(array(0 => 0, 3 => 3, 2 => 2, 1 => 1, 4 => 4, 9 => 9, 5 => 5, 6 => 6, 7 => 7), $trail);
-  }
-
-  /**
-   * Tests getActiveTrailIds() without preferred link.
-   *
-   * @covers ::getActiveTrailIds()
-   */
-  public function testGetActiveTrailIdsWithoutPreferredLink() {
-    $request = (new Request());
-    $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'test_route');
-    $this->requestStack->push($request);
-    $this->menuTree->setPath('test_menu', 'test/path');
-
-    $trail = $this->menuTree->getActiveTrailIds('test_menu');
-    $this->assertEquals(array(0 => 0), $trail);
-  }
-
-
-  /**
-   * Tests buildTree with simple menu_name and no parameters.
-   */
-  public function testBuildTreeWithoutParameters() {
-    $language = new Language(array('id' => 'en'));
-    $this->languageManager->expects($this->any())
-      ->method('getCurrentLanguage')
-      ->will($this->returnValue($language));
-
-    // Setup query and the query result.
-    $query = $this->getMock('Drupal\Core\Entity\Query\QueryInterface');
-    $this->entityQueryFactory->expects($this->once())
-      ->method('get')
-      ->with('menu_link')
-      ->will($this->returnValue($query));
-    $query->expects($this->once())
-      ->method('condition')
-      ->with('menu_name', 'test_menu');
-    $query->expects($this->once())
-      ->method('execute')
-      ->will($this->returnValue(array(1, 2, 3)));
-
-    $storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
-    $base = array(
-      'access' => TRUE,
-      'weight' => 0,
-      'title' => 'title',
-    );
-    $menu_link = $base + array(
-      'mlid' => 1,
-      'p1' => 3,
-      'p2' => 2,
-      'p3' => 1,
-    );
-    $links[1] = $menu_link;
-    $menu_link = $base + array(
-      'mlid' => 3,
-      'p1' => 3,
-      'depth' => 1,
-    );
-    $links[3] = $menu_link;
-    $menu_link = $base + array(
-      'mlid' => 2,
-      'p1' => 3,
-      'p2' => 2,
-      'depth' => 2,
-    );
-    $links[2] = $menu_link;
-    $storage->expects($this->once())
-      ->method('loadMultiple')
-      ->with(array(1, 2, 3))
-      ->will($this->returnValue($links));
-    $this->menuTree->setStorage($storage);
-
-    // Ensure that static/non static caching works.
-    // First setup no working caching.
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with('links:test_menu:tree-data:en:35786c7117b4e38d0f169239752ce71158266ae2f6e4aa230fbbb87bd699c0e3')
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(1))
-      ->method('set')
-      ->with('links:test_menu:tree-data:en:35786c7117b4e38d0f169239752ce71158266ae2f6e4aa230fbbb87bd699c0e3', $this->anything(), Cache::PERMANENT, array('menu' => 'test_menu'));
-
-    // Ensure that the static caching triggered.
-    $this->cacheBackend->expects($this->exactly(1))
-      ->method('get');
-
-    $this->menuTree->buildTree('test_menu');
-    $this->menuTree->buildTree('test_menu');
-  }
-
-  /**
-   * Tests the output with a single level.
-   *
-   * @covers ::renderTree
-   */
-  public function testOutputWithSingleLevel() {
-    $tree = array(
-      '1' => array(
-        'link' => array('mlid' => 1) + $this->defaultMenuLink,
-        'below' => array(),
-      ),
-      '2' => array(
-        'link' => array('mlid' => 2) + $this->defaultMenuLink,
-        'below' => array(),
-      ),
-    );
-
-    $output = $this->menuTree->renderTree($tree);
-
-    // Validate that the - in main-menu is changed into an underscore
-    $this->assertEquals($output['1']['#theme'], 'menu_link__main_menu', 'Hyphen is changed to an underscore on menu_link');
-    $this->assertEquals($output['2']['#theme'], 'menu_link__main_menu', 'Hyphen is changed to an underscore on menu_link');
-    $this->assertEquals($output['#theme_wrappers'][0], 'menu_tree__main_menu', 'Hyphen is changed to an underscore on menu_tree wrapper');
-  }
-
-  /**
-   * Tests the output method with a complex example.
-   *
-   * @covers ::renderTree
-   */
-  public function testOutputWithComplexData() {
-    $tree = array(
-      '1'=> array(
-        'link' => array('mlid' => 1, 'has_children' => 1, 'title' => 'Item 1', 'link_path' => 'a') + $this->defaultMenuLink,
-        'below' => array(
-          '2' => array('link' => array('mlid' => 2, 'title' => 'Item 2', 'link_path' => 'a/b') + $this->defaultMenuLink,
-            'below' => array(
-              '3' => array('link' => array('mlid' => 3, 'title' => 'Item 3', 'in_active_trail' => 0, 'link_path' => 'a/b/c') + $this->defaultMenuLink,
-                'below' => array()),
-              '4' => array('link' => array('mlid' => 4, 'title' => 'Item 4', 'in_active_trail' => 0, 'link_path' => 'a/b/d') + $this->defaultMenuLink,
-                'below' => array())
-            )
-          )
-        )
-      ),
-      '5' => array('link' => array('mlid' => 5, 'hidden' => 1, 'title' => 'Item 5', 'link_path' => 'e') + $this->defaultMenuLink, 'below' => array()),
-      '6' => array('link' => array('mlid' => 6, 'title' => 'Item 6', 'in_active_trail' => 0, 'access' => 0, 'link_path' => 'f') + $this->defaultMenuLink, 'below' => array()),
-      '7' => array('link' => array('mlid' => 7, 'title' => 'Item 7', 'in_active_trail' => 0, 'link_path' => 'g') + $this->defaultMenuLink, 'below' => array())
-    );
-
-    $output = $this->menuTree->renderTree($tree);
-
-    // Looking for child items in the data
-    $this->assertEquals( $output['1']['#below']['2']['#href'], 'a/b', 'Checking the href on a child item');
-    $this->assertTrue(in_array('active-trail', $output['1']['#below']['2']['#attributes']['class']), 'Checking the active trail class');
-    // Validate that the hidden and no access items are missing
-    $this->assertFalse(isset($output['5']), 'Hidden item should be missing');
-    $this->assertFalse(isset($output['6']), 'False access should be missing');
-    // Item 7 is after a couple hidden items. Just to make sure that 5 and 6 are
-    // skipped and 7 still included.
-    $this->assertTrue(isset($output['7']), 'Item after hidden items is present');
-  }
-
-  /**
-   * Tests menu tree access check with a single level.
-   *
-   * @covers ::checkAccess
-   */
-  public function testCheckAccessWithSingleLevel() {
-    $items = array(
-      array('mlid' => 1, 'route_name' => 'menu_test_1', 'depth' => 1, 'link_path' => 'menu_test/test_1', 'in_active_trail' => FALSE) + $this->defaultMenuLink,
-      array('mlid' => 2, 'route_name' => 'menu_test_2', 'depth' => 1, 'link_path' => 'menu_test/test_2', 'in_active_trail' => FALSE) + $this->defaultMenuLink,
-    );
-
-    // Register a menuLinkTranslate to mock the access.
-    $this->menuTree->menuLinkTranslateCallable = function(&$item) {
-      $item['access'] = $item['mlid'] == 1;
-    };
-
-    // Build the menu tree and check access for all of the items.
-    $tree = $this->menuTree->buildTreeData($items);
-
-    $this->assertCount(1, $tree);
-    $item = reset($tree);
-    $this->assertEquals($items[0], $item['link']);
-  }
-
-}
-
-class TestMenuTree extends MenuTree {
-
-  /**
-   * An alternative callable used for menuLinkTranslate.
-   * @var callable
-   */
-  public $menuLinkTranslateCallable;
-
-  /**
-   * Stores the preferred menu link per menu and path.
-   *
-   * @var array
-   */
-  protected $preferredMenuLink;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function menuLinkTranslate(&$item) {
-    if (isset($this->menuLinkTranslateCallable)) {
-      call_user_func_array($this->menuLinkTranslateCallable, array(&$item));
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function menuLinkGetPreferred($menu_name, $active_path) {
-    return isset($this->preferredMenuLink[$menu_name][$active_path]) ? $this->preferredMenuLink[$menu_name][$active_path] : NULL;
-  }
-
-  /**
-   * Set the storage.
-   *
-   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
-   *   The menu link storage.
-   */
-  public function setStorage(EntityStorageInterface $storage) {
-    $this->menuLinkStorage = $storage;
-  }
-
-  /**
-   * Sets the preferred menu link.
-   *
-   * @param string $menu_name
-   *   The menu name.
-   * @param string $active_path
-   *   The active path.
-   * @param array $menu_link
-   *   The preferred menu link.
-   */
-  public function setPreferredMenuLink($menu_name, $active_path, $menu_link) {
-    $this->preferredMenuLink[$menu_name][$active_path] = $menu_link;
-  }
-
-}
-
-}
-
-namespace {
-  if (!defined('MENU_MAX_DEPTH')) {
-    define('MENU_MAX_DEPTH', 9);
-  }
-}
diff --git a/core/modules/menu_link_content/menu_link_content.install b/core/modules/menu_link_content/menu_link_content.install
new file mode 100644
index 0000000..31fa93f
--- /dev/null
+++ b/core/modules/menu_link_content/menu_link_content.install
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the menu_link_content module.
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function menu_link_content_uninstall() {
+  // Find all the entities and then call the manager and delete all the plugins.
+  $query = \Drupal::entityQueryAggregate('menu_link_content');
+  $query->groupBy('uuid');
+  $result = $query->execute();
+  $uuids = array();
+  foreach ($result as $row) {
+    $uuids[] = $row['uuid'];
+  }
+
+  /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+  foreach ($uuids as $uuid) {
+    // Manually build the plugin ID, and remove it from the menu tree.
+    $menu_link_manager->removeDefinition("menu_link_content:$uuid", FALSE);
+  }
+}
diff --git a/core/modules/menu_link_content/menu_link_content.module b/core/modules/menu_link_content/menu_link_content.module
index 25dfb26..6d33dce 100644
--- a/core/modules/menu_link_content/menu_link_content.module
+++ b/core/modules/menu_link_content/menu_link_content.module
@@ -5,9 +5,30 @@
  * Allows administrators to create custom menu links.
  */
 
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\system\MenuInterface;
 
 /**
+ * Implements hook_help().
+ */
+function menu_link_content_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.menu_link_content':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Custom Menu Links module allows users to create menu links. These links can be translated if multiple languages are used for the site.');
+      if (\Drupal::moduleHandler()->moduleExists('menu_ui')) {
+        $output .= ' ' . t('It is required by the Menu UI module, which provides an interface for managing menus and menu links. See the <a href="!menu-help">Menu UI module help page</a> for more information.', array('!menu-help' => \Drupal::url('help.page', array('name' => 'menu_ui'))));
+      }
+      else {
+        $output .= ' ' . t('If you enable the Menu UI module, it provides an interface for managing menus and menu links.');
+      }
+      $output .= '</p>';
+      return $output;
+  }
+}
+
+/**
  * Implements hook_menu_delete().
  */
 function menu_link_content_menu_delete(MenuInterface $menu) {
diff --git a/core/modules/menu_link_content/menu_link_content.routing.yml b/core/modules/menu_link_content/menu_link_content.routing.yml
index f96b22d..b64b362 100644
--- a/core/modules/menu_link_content/menu_link_content.routing.yml
+++ b/core/modules/menu_link_content/menu_link_content.routing.yml
@@ -11,6 +11,9 @@ menu_link_content.link_edit:
   defaults:
     _entity_form: 'menu_link_content.default'
     _title: 'Edit menu link'
+  options:
+  # @todo Remove once https://www.drupal.org/node/2310475 is in.
+    _admin_route: TRUE
   requirements:
     _entity_access: 'menu_link_content.update'
 
diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php
index 4951cfb..7d79bd5 100644
--- a/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -65,7 +66,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $t_args = array('%title' => $this->entity->getTitle());
     $this->entity->delete();
     drupal_set_message($this->t('The menu link %title has been deleted.', $t_args));
diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
index c3f6395..727d8b2 100644
--- a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Menu\Form\MenuLinkFormInterface;
@@ -143,14 +144,7 @@ public function setMenuLinkInstance(MenuLinkInterface $menu_link) {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
-    return $this->buildEditForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildEditForm(array &$form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $this->setOperation('default');
     $this->init($form_state);
 
@@ -160,33 +154,17 @@ public function buildEditForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
-    $this->doValidate($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateEditForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->doValidate($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
-    return $this->submitEditForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitEditForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     // Remove button and internal Form API values from submitted values.
-    form_state_values_clean($form_state);
-    $this->entity = $this->buildEntity($form, $form_state);
-    $this->entity->save();
-    return $form_state;
+    parent::submit($form, $form_state);
+    $this->save($form, $form_state);
   }
 
   /**
@@ -232,9 +210,9 @@ protected function extractUrl($url) {
   /**
    * {@inheritdoc}
    */
-  public function extractFormValues(array &$form, array &$form_state) {
+  public function extractFormValues(array &$form, FormStateInterface $form_state) {
     $new_definition = array();
-    $new_definition['expanded'] = !empty($form_state['values']['expanded']) ? 1 : 0;
+    $new_definition['expanded'] = !empty($form_state['values']['expanded']['value']) ? 1 : 0;
     $new_definition['hidden'] = empty($form_state['values']['enabled']) ? 1 : 0;
     list($menu_name, $parent) = explode(':', $form_state['values']['menu_parent'], 2);
     if (!empty($menu_name)) {
@@ -263,7 +241,7 @@ public function extractFormValues(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     // We always show the internal path here.
@@ -337,7 +315,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $element = parent::actions($form, $form_state);
     $element['submit']['#button_type'] = 'primary';
     $element['delete']['#access'] = $this->entity->access('delete');
@@ -348,7 +326,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     $this->doValidate($form, $form_state);
 
     parent::validate($form, $form_state);
@@ -357,7 +335,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface $entity */
     $entity = parent::buildEntity($form, $form_state);
     $new_definition = $this->extractFormValues($form, $form_state);
@@ -378,7 +356,7 @@ public function buildEntity(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     // The entity is rebuilt in parent::submit().
     $menu_link = $this->entity;
     $saved = $menu_link->save();
@@ -406,10 +384,10 @@ public function save(array $form, array &$form_state) {
    *
    * @param array $form
    *   A nested array form elements comprising the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  protected function doValidate(array $form, array &$form_state) {
+  protected function doValidate(array $form, FormStateInterface $form_state) {
     $extracted = $this->extractUrl($form_state['values']['url']);
 
     // If both URL and route_name are empty, the entered value is not valid.
diff --git a/core/modules/menu_ui/menu_ui.admin.inc b/core/modules/menu_ui/menu_ui.admin.inc
index 0d7a0fd..f23093f 100644
--- a/core/modules/menu_ui/menu_ui.admin.inc
+++ b/core/modules/menu_ui/menu_ui.admin.inc
@@ -5,15 +5,19 @@
  * Administrative page callbacks for Menu UI module.
  */
 
+use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Render\Element;
 
 /**
  * Returns HTML for the menu overview form into a table.
  *
- * @param $variables
+ * @param array $variables
  *   An associative array containing:
  *   - form: A render element representing the form.
  *
+ * @return string
+ *   The themed HTML.
+ *
  * @ingroup themeable
  */
 function theme_menu_overview_form($variables) {
@@ -27,27 +31,28 @@ function theme_menu_overview_form($variables) {
   );
 
   $rows = array();
-  foreach (Element::children($form) as $mlid) {
-    if (isset($form[$mlid]['hidden'])) {
-      $element = &$form[$mlid];
+  foreach (Element::children($form) as $id) {
+    if (isset($form[$id]['#item'])) {
+      $element = &$form[$id];
 
       // Add special classes to be used for tabledrag.js.
-      $element['plid']['#attributes']['class'] = array('menu-plid');
-      $element['mlid']['#attributes']['class'] = array('menu-mlid');
+      $element['parent']['#attributes']['class'] = array('menu-parent');
+      $element['id']['#attributes']['class'] = array('menu-id');
       $element['weight']['#attributes']['class'] = array('menu-weight');
 
-      // Change the parent field to a hidden. This allows any value but hides the field.
-      $element['plid']['#type'] = 'hidden';
+      // Change the parent field to a hidden. This allows any value but hides
+      // the field.
+      $element['parent']['#type'] = 'hidden';
 
       $indent = array(
         '#theme' => 'indentation',
-        '#size' => $element['#item']['depth'] - 1,
+        '#size' => $element['#item']->depth - 1,
       );
 
       $row = array();
-      $row[] = drupal_render($indent) . drupal_render($element['title']);
-      $row[] = array('data' => drupal_render($element['hidden']), 'class' => array('checkbox', 'menu-enabled'));
-      $row[] = drupal_render($element['weight']) . drupal_render($element['plid']) . drupal_render($element['mlid']);
+      $row[] = SafeMarkup::set(drupal_render($indent) . drupal_render($element['title']));
+      $row[] = array('data' => drupal_render($element['enabled']), 'class' => array('checkbox', 'menu-enabled'));
+      $row[] = SafeMarkup::set(drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['id']));
       $row[] = drupal_render($element['operations']);
 
       $row = array_merge(array('data' => $row), $element['#attributes']);
@@ -71,11 +76,11 @@ function theme_menu_overview_form($variables) {
       array(
         'action' => 'match',
         'relationship' => 'parent',
-        'group' => 'menu-plid',
-        'subgroup' => 'menu-plid',
-        'source' => 'menu-mlid',
+        'group' => 'menu-parent',
+        'subgroup' => 'menu-parent',
+        'source' => 'menu-id',
         'hidden' => TRUE,
-        'limit' => MENU_MAX_DEPTH - 1,
+        'limit' => \Drupal::menuTree()->maxDepth() - 1,
       ),
       array(
         'action' => 'order',
diff --git a/core/modules/menu_ui/menu_ui.info.yml b/core/modules/menu_ui/menu_ui.info.yml
index 26611f1..f3bf1be 100644
--- a/core/modules/menu_ui/menu_ui.info.yml
+++ b/core/modules/menu_ui/menu_ui.info.yml
@@ -6,4 +6,4 @@ version: VERSION
 core: 8.x
 configure: menu_ui.overview_page
 dependencies:
-  - menu_link
+  - menu_link_content
diff --git a/core/modules/menu_ui/menu_ui.links.action.yml b/core/modules/menu_ui/menu_ui.links.action.yml
index 0834821..af8716f 100644
--- a/core/modules/menu_ui/menu_ui.links.action.yml
+++ b/core/modules/menu_ui/menu_ui.links.action.yml
@@ -1,6 +1,7 @@
-menu_ui_link_add:
-  route_name: menu_ui.link_add
+menu_ui.link_add:
+  route_name: menu_link_content.link_add
   title: 'Add link'
+  class: \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd
   appears_on:
     - menu_ui.menu_edit
 
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index 70b5b59..8dbb4e2 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -10,13 +10,14 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\block\BlockPluginInterface;
+use Drupal\Core\Menu\MenuLinkInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\menu_link_content\Entity\MenuLinkContent;
 use Drupal\node\NodeTypeInterface;
 use Drupal\system\Entity\Menu;
 use Symfony\Component\HttpFoundation\JsonResponse;
-use Drupal\menu_link\Entity\MenuLink;
-use Drupal\menu_link\MenuLinkStorage;
 use Drupal\node\NodeInterface;
 
 /**
@@ -72,31 +73,11 @@ function menu_ui_entity_type_build(array &$entity_types) {
     ->setFormClass('edit', 'Drupal\menu_ui\MenuForm')
     ->setFormClass('delete', 'Drupal\menu_ui\Form\MenuDeleteForm')
     ->setListBuilderClass('Drupal\menu_ui\MenuListBuilder')
-    ->setLinkTemplate('add-form', 'menu_ui.link_add')
+    ->setLinkTemplate('add-form', 'menu_ui.menu_add')
     ->setLinkTemplate('delete-form', 'menu_ui.delete_menu')
     ->setLinkTemplate('edit-form', 'menu_ui.menu_edit');
-
-  $entity_types['menu_link']
-    ->setFormClass('delete', 'Drupal\menu_ui\Form\MenuLinkDeleteForm')
-    ->setFormClass('reset', 'Drupal\menu_ui\Form\MenuLinkResetForm')
-    ->setLinkTemplate('delete-form', 'menu_ui.link_delete');
 }
 
-/**
- * Implements hook_entity_bundle_info().
- */
-function menu_ui_entity_bundle_info() {
-  $bundles = array();
-  $config_names = \Drupal::configFactory()->listAll('system.menu.');
-  foreach ($config_names as $config_name) {
-    $config = \Drupal::config($config_name);
-    $bundles['menu_link'][$config->get('id')] = array(
-      'label' => $config->get('label'),
-    );
-  }
-
-  return $bundles;
-}
 
 /**
  * Implements hook_theme().
@@ -119,23 +100,6 @@ function menu_ui_menu_insert(Menu $menu) {
   if (\Drupal::moduleHandler()->moduleExists('block')) {
     \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
   }
-
-  if ($menu->isSyncing()) {
-    return;
-  }
-
-  // Make sure the menu is present in the active menus variable so that its
-  // items may appear in the menu active trail.
-  // See menu_set_active_menu_names().
-  $config = \Drupal::config('system.menu');
-
-  $active_menus = $config->get('active_menus_default') ?: array_keys(menu_ui_get_menus());
-  if (!in_array($menu->id(), $active_menus)) {
-    $active_menus[] = $menu->id();
-    $config
-      ->set('active_menus_default', $active_menus)
-      ->save();
-  }
 }
 
 /**
@@ -154,20 +118,9 @@ function menu_ui_menu_update(Menu $menu) {
  */
 function menu_ui_menu_predelete(Menu $menu) {
   // Delete all links from the menu.
-  menu_delete_links($menu->id());
-
-  // Remove menu from active menus variable.
-  $config = \Drupal::config('system.menu');
-  $active_menus = $config->get('active_menus_default') ?: array_keys(menu_ui_get_menus());
-  if (in_array($menu->id(), $active_menus)) {
-    $active_menus = array_diff($active_menus, array($menu->id()));
-    // Prevent the gap left by the removed menu from causing array indices to
-    // be saved.
-    $active_menus = array_values($active_menus);
-    $config
-      ->set('active_menus_default', $active_menus)
-      ->save();
-  }
+  /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+  $menu_link_manager->deleteLinksInMenu($menu->id());
 }
 
 /**
@@ -183,110 +136,13 @@ function menu_ui_menu_delete(Menu $menu) {
 }
 
 /**
- * Returns a list of menu links that are valid possible parents for the given
- * menu link.
- *
- * @param array $menus
- *   An array of menu names and titles, such as from menu_ui_get_menus().
- * @param \Drupal\menu_link\Entity\MenuLink $menu_link
- *   The menu link for which to generate a list of parents.
- *   If $menu_link->id() == 0 then the complete tree is returned.
- * @param string $type
- *   The node type for which to generate a list of parents.
- *   If $item itself is a node type then $type is ignored.
- *
- * @return array
- *   An array of menu link titles keyed by a string containing the menu name and
- *   mlid. The list excludes the given item and its children.
- *
- * @todo This has to be turned into a #process form element callback. The
- *   'override_parent_selector' variable is entirely superfluous.
- */
-function menu_ui_parent_options(array $menus, MenuLink $menu_link = NULL, $type = NULL) {
-  // The menu_links table can be practically any size and we need a way to
-  // allow contrib modules to provide more scalable pattern choosers.
-  // hook_form_alter is too late in itself because all the possible parents are
-  // retrieved here, unless override_parent_selector is set to TRUE.
-  if (\Drupal::config('menu_ui.settings')->get('override_parent_selector')) {
-    return array();
-  }
-
-  if (!$menu_link) {
-    $menu_link = entity_create('menu_link', array('mlid' => 0));
-  }
-
-  $available_menus = array();
-  if (!$type) {
-    // If no node type is set, use all menus given to this function.
-    $available_menus = $menus;
-  }
-  else {
-    // If a node type is set, use all available menus for this type.
-    $type_menus = \Drupal::config("menu.entity.node.$type")->get('available_menus');
-    foreach ($type_menus as $menu) {
-      $available_menus[$menu] = $menu;
-    }
-  }
-
-  return _menu_ui_get_options($menus, $available_menus, $menu_link);
-}
-
-/**
- * Helper function to get the items of the given menu.
- */
-function _menu_ui_get_options($menus, $available_menus, $item) {
-  // If the item has children, there is an added limit to the depth of valid parents.
-  if (isset($item['parent_depth_limit'])) {
-    $limit = $item['parent_depth_limit'];
-  }
-  else {
-    $limit = _menu_ui_parent_depth_limit($item);
-  }
-
-  /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-  $menu_tree = \Drupal::service('menu_link.tree');
-
-  $options = array();
-  foreach ($menus as $menu_name => $title) {
-    if (isset($available_menus[$menu_name])) {
-      $tree = $menu_tree->buildAllData($menu_name, NULL);
-      $options[$menu_name . ':0'] = '<' . $title . '>';
-      _menu_ui_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit);
-    }
-  }
-  return $options;
-}
-
-/**
- * Recursive helper function for menu_ui_parent_options().
- */
-function _menu_ui_parents_recurse($tree, $menu_name, $indent, &$options, $exclude, $depth_limit) {
-  foreach ($tree as $data) {
-    if ($data['link']['depth'] > $depth_limit) {
-      // Don't iterate through any links on this level.
-      break;
-    }
-    if ($data['link']['mlid'] != $exclude && $data['link']['hidden'] >= 0) {
-      $title = $indent . ' ' . truncate_utf8($data['link']['title'], 30, TRUE, FALSE);
-      if ($data['link']['hidden']) {
-        $title .= ' (' . t('disabled') . ')';
-      }
-      $options[$menu_name . ':' . $data['link']['mlid']] = $title;
-      if ($data['below']) {
-        _menu_ui_parents_recurse($data['below'], $menu_name, $indent . '--', $options, $exclude, $depth_limit);
-      }
-    }
-  }
-}
-
-/**
  * Implements hook_block_view_BASE_BLOCK_ID_alter() for 'system_menu_block'.
  */
 function menu_ui_block_view_system_menu_block_alter(array &$build, BlockPluginInterface $block) {
   // Add contextual links for system menu blocks.
   $menus = menu_list_system_menus();
   $menu_name = $block->getDerivativeId();
-  if (isset($menus[$menu_name])) {
+  if (isset($menus[$menu_name]) && isset($build['content'])) {
     $build['#contextual_links']['menu'] = array(
       'route_parameters' => array('menu' => $menu_name),
     );
@@ -316,7 +172,7 @@ function menu_ui_node_type_insert(NodeTypeInterface $type) {
   }
   \Drupal::config('menu.entity.node.' . $type->id())
     ->set('available_menus', array('main'))
-    ->set('parent', 'main:0')
+    ->set('parent', 'main:')
     ->save();
 }
 
@@ -334,25 +190,35 @@ function menu_ui_node_type_delete(NodeTypeInterface $type) {
  * Helper for hook_ENTITY_TYPE_insert() and hook_ENTITY_TYPE_update() for nodes.
  */
 function menu_ui_node_save(EntityInterface $node) {
-  if (isset($node->menu)) {
-    $link = &$node->menu;
-    if (empty($link['enabled'])) {
-      if (!$link->isNew()) {
-        menu_link_delete($link['mlid']);
-      }
-    }
-    elseif (trim($link['link_title'])) {
-      $link['link_title'] = trim($link['link_title']);
-      $link['link_path'] = 'node/' . $node->id();
-      if (trim($link['description'])) {
-        $link['options']['attributes']['title'] = trim($link['description']);
+  if (!empty($node->menu)) {
+    /** @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface $entity */
+    $definition = $node->menu;
+    if (trim($definition['title'])) {
+      if (!empty($definition['entity_id'])) {
+        $entity = entity_load('menu_link_content', $definition['entity_id']);
+        $entity->hidden->value = 0;
+        $entity->title->value = trim($definition['title']);
+        $entity->description->value = trim($definition['description']);
+        $entity->menu_name->value = $definition['menu_name'];
+        $entity->parent->value = $definition['parent'];
+        $entity->weight->value = isset($definition['weight']) ? $definition['weight'] : 0;
       }
       else {
-        // If the description field was left empty, remove the title attribute
-        // from the menu link.
-        unset($link['options']['attributes']['title']);
+        // Create a new menu_link_content entity.
+        $entity = entity_create('menu_link_content', array(
+          'title' => trim($definition['title']),
+          'description' => trim($definition['description']),
+          'route_name' => 'node.view',
+          'route_parameters' => array('node' => $node->id()),
+          'menu_name' => $definition['menu_name'],
+          'parent' => $definition['parent'],
+          'weight' => isset($definition['weight']) ? $definition['weight'] : 0,
+          'hidden' => 0,
+          'bundle' => 'menu_link_content',
+          'langcode' => $node->getUntranslated()->language()->id,
+        ));
       }
-      if (!menu_link_save($link)) {
+      if (!$entity->save()) {
         drupal_set_message(t('There was an error saving the menu link.'), 'error');
       }
     }
@@ -363,82 +229,87 @@ function menu_ui_node_save(EntityInterface $node) {
  * Implements hook_ENTITY_TYPE_predelete() for node entities.
  */
 function menu_ui_node_predelete(EntityInterface $node) {
-  // Delete all Menu UI module links that point to this node.
-  $query = \Drupal::entityQuery('menu_link')
-    ->condition('link_path', 'node/' . $node->id())
-    ->condition('module', 'menu');
-  $result = $query->execute();
+  // Delete all MenuLinkContent links that point to this node.
+  /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+  $result = $menu_link_manager->loadLinksByRoute('node.view', array('node' => $node->id()));
 
   if (!empty($result)) {
-    menu_link_delete_multiple($result);
+    foreach ($result as $id => $instance) {
+      if ($instance->isDeletable() && strpos($id, 'menu_link_content:') === 0) {
+        $instance->deleteLink();
+      }
+    }
   }
 }
 
 /**
  * Implements hook_node_prepare_form().
  */
-function menu_ui_node_prepare_form(NodeInterface $node, $operation, array &$form_state) {
-  if (empty($node->menu)) {
+function menu_ui_node_prepare_form(NodeInterface $node, $operation, FormStateInterface $form_state) {
+  if (empty($form_state['menu_link_definition'])) {
     // Prepare the node for the edit form so that $node->menu always exists.
     $node_type_config = \Drupal::config('menu.entity.node.' . $node->getType());
     $menu_name = strtok($node_type_config->get('parent'), ':');
-    $menu_link = FALSE;
+    $definition = FALSE;
     if ($node->id()) {
-      $mlid = FALSE;
+      $id = FALSE;
       // Give priority to the default menu
       $type_menus = $node_type_config->get('available_menus');
       if (in_array($menu_name, $type_menus)) {
-        $query = \Drupal::entityQuery('menu_link')
-          ->condition('link_path', 'node/' . $node->id())
+        $query = \Drupal::entityQuery('menu_link_content')
+          ->condition('route_name', 'node.view')
+          ->condition('route_parameters', serialize(array('node' => $node->id())))
           ->condition('menu_name', $menu_name)
-          ->condition('module', 'menu_ui')
-          ->sort('mlid', 'ASC')
+          ->sort('id', 'ASC')
           ->range(0, 1);
         $result = $query->execute();
 
-        $mlid = (!empty($result)) ? reset($result) : FALSE;
+        $id = (!empty($result)) ? reset($result) : FALSE;
       }
       // Check all allowed menus if a link does not exist in the default menu.
-      if (!$mlid && !empty($type_menus)) {
-        $query = \Drupal::entityQuery('menu_link')
-          ->condition('link_path', 'node/' . $node->id())
+      if (!$id && !empty($type_menus)) {
+        $query = \Drupal::entityQuery('menu_link_content')
+          ->condition('route_name', 'node.view')
+          ->condition('route_parameters', serialize(array('node' => $node->id())))
           ->condition('menu_name', array_values($type_menus), 'IN')
-          ->condition('module', 'menu_ui')
-          ->sort('mlid', 'ASC')
+          ->sort('id', 'ASC')
           ->range(0, 1);
         $result = $query->execute();
 
-        $mlid = (!empty($result)) ? reset($result) : FALSE;
+        $id = (!empty($result)) ? reset($result) : FALSE;
       }
-      if ($mlid) {
-        $menu_link = menu_link_load($mlid);
+      if ($id) {
+        $menu_link = MenuLinkContent::load($id);
+        $definition = array(
+          'entity_id' => $menu_link->id(),
+          'id' => $menu_link->getPluginId(),
+          'title' => $menu_link->getTitle(),
+          'description' => $menu_link->getDescription(),
+          'menu_name' => $menu_link->getMenuName(),
+          'parent' => $menu_link->getParentId(),
+          'weight' => $menu_link->getWeight(),
+        );
       }
     }
 
-    if (!$menu_link) {
-      $menu_link = entity_create('menu_link', array(
-        'mlid' => 0,
-        'plid' => 0,
+    if (!$definition) {
+      $definition = array(
+        'entity_id' => 0,
+        'id' => '',
+        'title' => '',
+        'description' => '',
         'menu_name' => $menu_name,
-      ));
+        'parent' => '',
+        'weight' => 0,
+      );
     }
     // Set default values.
-    $node->menu = $menu_link;
-  }
-  // Find the depth limit for the parent select.
-  if (!isset($node->menu['parent_depth_limit'])) {
-    $node->menu['parent_depth_limit'] = _menu_ui_parent_depth_limit($node->menu);
+    $form_state['menu_link_definition'] = $definition;
   }
 }
 
 /**
- * Find the depth limit for items in the parent select.
- */
-function _menu_ui_parent_depth_limit($item) {
-  return MENU_MAX_DEPTH - 1 - (($item['mlid'] && $item['has_children']) ? entity_get_controller('menu_link')->findChildrenRelativeDepth($item) : 0);
-}
-
-/**
  * Implements hook_form_BASE_FORM_ID_alter() for node_form.
  *
  * Adds menu item fields to the node form.
@@ -449,11 +320,25 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
   // Generate a list of possible parents (not including this link or descendants).
   // @todo This must be handled in a #process handler.
   $node = $form_state['controller']->getEntity();
-  $link = $node->menu;
+  $definition = $form_state['menu_link_definition'];
   $type = $node->getType();
-  $options = menu_ui_parent_options(menu_ui_get_menus(), $link, $type);
+  /** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
+  $menu_parent_selector = \Drupal::service('menu.parent_form_selector');
+  $menu_names = menu_ui_get_menus();
+  $type_menus = \Drupal::config("menu.entity.node.$type")->get('available_menus');
+  $available_menus = array();
+  foreach ($type_menus as $menu) {
+    $available_menus[$menu] = $menu_names[$menu];
+  }
+  if ($definition['id']) {
+    $default = $definition['menu_name'] . ':' . $definition['parent'];
+  }
+  else {
+    $default = \Drupal::config('menu.entity.node.'.$type)->get('parent');
+  }
+  $parent_element = $menu_parent_selector->parentSelectElement($default,  $definition['id'], $available_menus);
   // If no possible parent menu items were found, there is nothing to display.
-  if (empty($options)) {
+  if (empty($parent_element)) {
     return;
   }
 
@@ -461,7 +346,7 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
     '#type' => 'details',
     '#title' => t('Menu settings'),
     '#access' => \Drupal::currentUser()->hasPermission('administer menu'),
-    '#open' => !empty($link['link_title']),
+    '#open' => (bool) $definition['id'],
     '#group' => 'advanced',
     '#attached' => array(
       'library' => array('menu/drupal.menu'),
@@ -473,7 +358,7 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
   $form['menu']['enabled'] = array(
     '#type' => 'checkbox',
     '#title' => t('Provide a menu link'),
-    '#default_value' => (int) (bool) $link['mlid'],
+    '#default_value' => (int) (bool) $definition['id'],
   );
   $form['menu']['link'] = array(
     '#type' => 'container',
@@ -486,57 +371,32 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
   );
 
   // Populate the element with the link data.
-  foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
-    $form['menu']['link'][$key] = array('#type' => 'value', '#value' => $link[$key]);
+  foreach (array('id', 'entity_id') as $key) {
+    $form['menu']['link'][$key] = array('#type' => 'value', '#value' => $definition[$key]);
   }
 
-  $form['menu']['link']['link_title'] = array(
+  $form['menu']['link']['title'] = array(
     '#type' => 'textfield',
     '#title' => t('Menu link title'),
-    '#default_value' => $link['link_title'],
+    '#default_value' => $definition['title'],
   );
 
   $form['menu']['link']['description'] = array(
     '#type' => 'textarea',
     '#title' => t('Description'),
-    '#default_value' => isset($link['options']['attributes']['title']) ? $link['options']['attributes']['title'] : '',
+    '#default_value' => $definition['description'],
     '#rows' => 1,
     '#description' => t('Shown when hovering over the menu link.'),
   );
 
-  if ($link['mlid']) {
-    $default = $link['menu_name'] . ':' . $link['plid'];
-  }
-  else {
-    $default = \Drupal::config('menu.entity.node.'.$type)->get('parent');
-  }
-  // If the current parent menu item is not present in options, use the first
-  // available option as default value.
-  // @todo User should not be allowed to access menu link settings in such a
-  // case.
-  if (!isset($options[$default])) {
-    $array = array_keys($options);
-    $default = reset($array);
-  }
-  $form['menu']['link']['parent'] = array(
-    '#type' => 'select',
-    '#title' => t('Parent item'),
-    '#default_value' => $default,
-    '#options' => $options,
-    '#attributes' => array('class' => array('menu-parent-select')),
-  );
+  $form['menu']['link']['menu_parent'] = $parent_element;
+  $form['menu']['link']['menu_parent']['#title'] = t('Parent item');
+  $form['menu']['link']['menu_parent']['#attributes']['class'][] = 'menu-parent-select';
 
-  // Get number of items in menu so the weight selector is sized appropriately.
-  $delta = entity_get_controller('menu_link')->countMenuLinks($link->menu_name);
-  if ($delta < 50) {
-    // Old hardcoded value
-    $delta = 50;
-  }
   $form['menu']['link']['weight'] = array(
-    '#type' => 'weight',
+    '#type' => 'number',
     '#title' => t('Weight'),
-    '#delta' => $delta,
-    '#default_value' => $link['weight'],
+    '#default_value' => $definition['weight'],
     '#description' => t('Menu links with lower weights are displayed before links with higher weights.'),
   );
 }
@@ -548,18 +408,26 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
  */
 function menu_ui_node_submit(EntityInterface $node, $form, $form_state) {
   if (!empty($form_state['values']['menu'])) {
-    $original_menu_id = !empty($node->menu) ? $node->menu->id() : NULL;
-    $node->menu = entity_create('menu_link', $form_state['values']['menu']);
-    // @todo Do not create a new entity in order to update it, see
-    //   https://drupal.org/node/2241865
-    // If this menu had a previous menu link associated, mark it as not new.
-    if ($original_menu_id) {
-      $node->menu->setOriginalId($original_menu_id);
+    $definition = $form_state['values']['menu'];
+    if (empty($definition['enabled'])) {
+      if ($definition['entity_id']) {
+        $entity = entity_load('menu_link_content', $definition['entity_id']);
+        $entity->delete();
+      }
     }
-    // Decompose the selected menu parent option into 'menu_name' and 'plid', if
-    // the form used the default parent selection widget.
-    if (!empty($form_state['values']['menu']['parent'])) {
-      list($node->menu['menu_name'], $node->menu['plid']) = explode(':', $form_state['values']['menu']['parent']);
+    elseif (trim($definition['title']))  {
+      // Decompose the selected menu parent option into 'menu_name' and 'parent',
+      // if the form used the default parent selection widget.
+      if (!empty($definition['menu_parent'])) {
+        list($menu_name, $parent) = explode(':', $definition['menu_parent'], 2);
+        $definition['menu_name'] = $menu_name;
+        $definition['parent'] = $parent;
+      }
+      // @todo Figure out how to save this data without adding non-Field API
+      //   properties to the node entity. https://www.drupal.org/node/2310173
+      //   We have to tack this onto the node so we can save it later when we
+      //   have a node ID for any new node.
+      $node->menu = $definition;
     }
   }
 }
@@ -573,6 +441,8 @@ function menu_ui_node_submit(EntityInterface $node, $form, $form_state) {
  * @see menu_ui_form_node_type_form_submit().
  */
 function menu_ui_form_node_type_form_alter(&$form, $form_state) {
+  /** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
+  $menu_parent_selector = \Drupal::service('menu.parent_form_selector');
   $menu_options = menu_ui_get_menus();
   $type = $form_state['controller']->getEntity();
   if ($type->id()) {
@@ -581,7 +451,7 @@ function menu_ui_form_node_type_form_alter(&$form, $form_state) {
   else {
     $config_values = array(
       'available_menus' => array('main'),
-      'parent' => 'main:0',
+      'parent' => 'main:',
     );
   }
   $form['menu'] = array(
@@ -599,12 +469,12 @@ function menu_ui_form_node_type_form_alter(&$form, $form_state) {
     '#options' => $menu_options,
     '#description' => t('The menus available to place links in for this content type.'),
   );
-  // To avoid an 'illegal option' error after saving the form we have to load
-  // all available menu items.
-  // Otherwise it is not possible to dynamically add options to the list.
-  // @todo Convert menu_ui_parent_options() into a #process callback.
-  $menu_link = entity_create('menu_link', array('mlid' => 0));
-  $options = menu_ui_parent_options(menu_ui_get_menus(), $menu_link);
+  // @todo See if we can avoid pre-loading all options by changing the form or
+  //   using a #process callback. https://www.drupal.org/node/2310319
+  //   To avoid an 'illegal option' error after saving the form we have to load
+  //   all available menu parents. Otherwise, it is not possible to dynamically
+  //   add options to the list using ajax.
+  $options = $menu_parent_selector->getParentSelectOptions('');
   $form['menu']['menu_parent'] = array(
     '#type' => 'select',
     '#title' => t('Default parent item'),
@@ -636,7 +506,8 @@ function menu_ui_form_node_type_form_submit(&$form, $form_state) {
  * @param $all
  *   If FALSE return only user-added menus, or if TRUE also include
  *   the menus defined by the system.
- * @return
+ *
+ * @return array
  *   An array with the machine-readable names as the keys, and human-readable
  *   titles as the values.
  */
@@ -661,3 +532,19 @@ function menu_ui_preprocess_block(&$variables) {
     $variables['attributes']['role'] = 'navigation';
   }
 }
+
+
+/**
+ * Implements hook_system_breadcrumb_alter().
+ */
+function menu_ui_system_breadcrumb_alter(array &$breadcrumb, RouteMatchInterface $route_match, array $context) {
+  // Custom breadcrumb behavior for editing menu links, we append a link to
+  // the menu in which the link is found.
+  if (($route_match->getRouteName() == 'menu_ui.link_edit') && $menu_link = $route_match->getParameter('menu_link_plugin')) {
+    if (($menu_link instanceof MenuLinkInterface)) {
+      // Add a link to the menu admin screen.
+      $menu = entity_load('menu', $menu_link->getMenuName());
+      $breadcrumb[] = \Drupal::l($menu->label(), 'menu_ui.menu_edit', array('menu' => $menu->id()));
+    }
+  }
+}
diff --git a/core/modules/menu_ui/menu_ui.routing.yml b/core/modules/menu_ui/menu_ui.routing.yml
index 4be3bbf..b095c34 100644
--- a/core/modules/menu_ui/menu_ui.routing.yml
+++ b/core/modules/menu_ui/menu_ui.routing.yml
@@ -21,37 +21,30 @@ menu_ui.parent_options_js:
   requirements:
     _permission: 'administer menu'
 
-menu_ui.link_add:
-  path: '/admin/structure/menu/manage/{menu}/add'
-  defaults:
-    _content: '\Drupal\menu_ui\Controller\MenuController::addLink'
-    _title: 'Add menu link'
-  requirements:
-    _entity_create_access: 'menu_link'
-
 menu_ui.link_edit:
-  path: '/admin/structure/menu/item/{menu_link}/edit'
+  path: '/admin/structure/menu/link/{menu_link_plugin}/edit'
   defaults:
-    _entity_form: 'menu_link'
+    _form: 'Drupal\menu_ui\Form\MenuLinkEditForm'
     _title: 'Edit menu link'
+  options:
+    parameters:
+      menu_link_plugin:
+        type: menu_link_plugin
   requirements:
-    _entity_access: 'menu_link.update'
+    _permission: 'administer menu'
 
 menu_ui.link_reset:
-  path: '/admin/structure/menu/item/{menu_link}/reset'
+  path: '/admin/structure/menu/link/{menu_link_plugin}/reset'
   defaults:
-    _entity_form: 'menu_link.reset'
+    _form: 'Drupal\menu_ui\Form\MenuLinkResetForm'
     _title: 'Reset menu link'
+  options:
+    parameters:
+      menu_link_plugin:
+        type: menu_link_plugin
   requirements:
-    _entity_access: 'menu_link.reset'
-
-menu_ui.link_delete:
-  path: '/admin/structure/menu/item/{menu_link}/delete'
-  defaults:
-    _entity_form: 'menu_link.delete'
-    _title: 'Delete menu link'
-  requirements:
-    _entity_access: 'menu_link.delete'
+    _permission: 'administer menu'
+    _custom_access: '\Drupal\menu_ui\Form\MenuLinkResetForm::linkIsResettable'
 
 menu_ui.menu_add:
   path: '/admin/structure/menu/add'
diff --git a/core/modules/menu_ui/src/Controller/MenuController.php b/core/modules/menu_ui/src/Controller/MenuController.php
index fad5de5..95788bd 100644
--- a/core/modules/menu_ui/src/Controller/MenuController.php
+++ b/core/modules/menu_ui/src/Controller/MenuController.php
@@ -9,7 +9,9 @@
 
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Menu\MenuParentFormSelectorInterface;
 use Drupal\system\MenuInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -19,6 +21,30 @@
 class MenuController extends ControllerBase {
 
   /**
+   * The menu parent form service.
+   *
+   * @var \Drupal\Core\Menu\MenuParentFormSelectorInterface
+   */
+  protected $menuParentSelector;
+
+  /**
+   * Creates a new MenuController object.
+   *
+   * @param \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_form
+   *   The menu parent form service.
+   */
+  public function __construct(MenuParentFormSelectorInterface $menu_parent_form) {
+    $this->menuParentSelector = $menu_parent_form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static($container->get('menu.parent_form_selector'));
+  }
+
+  /**
    * Gets all the available menus and menu items as a JavaScript array.
    *
    * @param \Symfony\Component\HttpFoundation\Request $request
@@ -34,30 +60,12 @@ public function getParentOptions(Request $request) {
         $available_menus[$menu] = $menu;
       }
     }
-    $options = _menu_ui_get_options(menu_ui_get_menus(), $available_menus, array('mlid' => 0));
+    $options = $this->menuParentSelector->getParentSelectOptions('', $available_menus);
 
     return new JsonResponse($options);
   }
 
   /**
-   * Provides the menu link submission form.
-   *
-   * @param \Drupal\system\MenuInterface $menu
-   *   An entity representing a custom menu.
-   *
-   * @return array
-   *   Returns the menu link submission form.
-   */
-  public function addLink(MenuInterface $menu) {
-    $menu_link = $this->entityManager()->getStorage('menu_link')->create(array(
-      'mlid' => 0,
-      'plid' => 0,
-      'menu_name' => $menu->id(),
-    ));
-    return $this->entityFormBuilder()->getForm($menu_link);
-  }
-
-  /**
    * Route title callback.
    *
    * @param \Drupal\system\MenuInterface $menu
diff --git a/core/modules/menu_ui/src/Form/MenuDeleteForm.php b/core/modules/menu_ui/src/Form/MenuDeleteForm.php
index 13cbf94..2332b40 100644
--- a/core/modules/menu_ui/src/Form/MenuDeleteForm.php
+++ b/core/modules/menu_ui/src/Form/MenuDeleteForm.php
@@ -9,7 +9,8 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityConfirmFormBase;
-use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Menu\MenuLinkManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -19,11 +20,11 @@
 class MenuDeleteForm extends EntityConfirmFormBase {
 
   /**
-   * The menu link storage.
+   * The menu link manager.
    *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
    */
-  protected $storage;
+  protected $menuLinkManager;
 
   /**
    * The database connection.
@@ -35,13 +36,13 @@ class MenuDeleteForm extends EntityConfirmFormBase {
   /**
    * Constructs a new MenuDeleteForm.
    *
-   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
-   *   The menu link storage.
+   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
+   *   The menu link manager.
    * @param \Drupal\Core\Database\Connection $connection
    *   The database connection.
    */
-  public function __construct(EntityStorageInterface $storage, Connection $connection) {
-    $this->storage = $storage;
+  public function __construct(MenuLinkManagerInterface $menu_link_manager, Connection $connection) {
+    $this->menuLinkManager = $menu_link_manager;
     $this->connection = $connection;
   }
 
@@ -50,7 +51,7 @@ public function __construct(EntityStorageInterface $storage, Connection $connect
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('entity.manager')->getStorage('menu_link'),
+      $container->get('plugin.manager.menu.link'),
       $container->get('database')
     );
   }
@@ -74,7 +75,7 @@ public function getCancelUrl() {
    */
   public function getDescription() {
     $caption = '';
-    $num_links = $this->storage->countMenuLinks($this->entity->id());
+    $num_links = $this->menuLinkManager->countMenuLinks($this->entity->id());
     if ($num_links) {
       $caption .= '<p>' . format_plural($num_links, '<strong>Warning:</strong> There is currently 1 menu link in %title. It will be deleted (system-defined items will be reset).', '<strong>Warning:</strong> There are currently @count menu links in %title. They will be deleted (system-defined links will be reset).', array('%title' => $this->entity->label())) . '</p>';
     }
@@ -92,7 +93,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = new Url('menu_ui.overview_page');
 
     // Locked menus may not be deleted.
@@ -100,21 +101,16 @@ public function submit(array $form, array &$form_state) {
       return;
     }
 
-    // Reset all the menu links defined by the menu_link.static service.
-    $result = \Drupal::entityQuery('menu_link')
-      ->condition('menu_name', $this->entity->id())
-      ->condition('module', '', '>')
-      ->condition('machine_name', '', '>')
-      ->sort('depth', 'ASC')
-      ->execute();
-    $menu_links = $this->storage->loadMultiple($result);
-    foreach ($menu_links as $link) {
-      $link->reset();
-    }
-
     // Delete all links to the overview page for this menu.
-    $menu_links = $this->storage->loadByProperties(array('link_path' => 'admin/structure/menu/manage/' . $this->entity->id()));
-    menu_link_delete_multiple(array_keys($menu_links));
+    // @todo Add a more generic helper function to the menu link plugin
+    //   manager to remove links to a entity or other ID used as a route
+    //   parameter that is being removed. Also, consider moving this to
+    //   menu_ui.module as part of a generic response to entity deletion.
+    //   https://www.drupal.org/node/2310329
+    $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_ui.menu_edit', array('menu' => $this->entity->id()), TRUE);
+    foreach ($menu_links as $id => $link) {
+      $this->menuLinkManager->removeDefinition($id);
+    }
 
     // Delete the custom menu and all its menu links.
     $this->entity->delete();
diff --git a/core/modules/menu_ui/src/Form/MenuLinkDeleteForm.php b/core/modules/menu_ui/src/Form/MenuLinkDeleteForm.php
deleted file mode 100644
index 0a971d9..0000000
--- a/core/modules/menu_ui/src/Form/MenuLinkDeleteForm.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu_ui\Form\MenuLinkDeleteForm.
- */
-
-namespace Drupal\menu_ui\Form;
-
-use Drupal\Core\Entity\EntityConfirmFormBase;
-use Drupal\Core\Url;
-
-/**
- * Defines a confirmation form for deletion of a single menu link.
- */
-class MenuLinkDeleteForm extends EntityConfirmFormBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    return t('Are you sure you want to delete the custom menu link %item?', array('%item' => $this->entity->link_title));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelUrl() {
-    return new Url('menu_ui.menu_edit', array(
-      'menu' => $this->entity->menu_name,
-    ));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submit(array $form, array &$form_state) {
-    menu_link_delete($this->entity->id());
-    $t_args = array('%title' => $this->entity->link_title);
-    drupal_set_message(t('The menu link %title has been deleted.', $t_args));
-    watchdog('menu', 'Deleted menu link %title.', $t_args, WATCHDOG_NOTICE);
-    $form_state['redirect_route'] = $this->getCancelUrl();
-  }
-
-}
diff --git a/core/modules/menu_ui/src/Form/MenuLinkEditForm.php b/core/modules/menu_ui/src/Form/MenuLinkEditForm.php
index 4e87ffb..ebd691f 100644
--- a/core/modules/menu_ui/src/Form/MenuLinkEditForm.php
+++ b/core/modules/menu_ui/src/Form/MenuLinkEditForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Menu\MenuLinkInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -22,7 +23,7 @@
 class MenuLinkEditForm extends FormBase {
 
   /**
-   * The class resolver
+   * The class resolver.
    *
    * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
    */
@@ -60,7 +61,7 @@ public function getFormId() {
    * @param \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin
    *   The plugin instance to use for this form.
    */
-  public function buildForm(array $form, array &$form_state, MenuLinkInterface $menu_link_plugin = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, MenuLinkInterface $menu_link_plugin = NULL) {
     $form['menu_link_id'] = array(
       '#type' => 'value',
       '#value' => $menu_link_plugin->getPluginId(),
@@ -83,14 +84,14 @@ public function buildForm(array $form, array &$form_state, MenuLinkInterface $me
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form['#plugin_form']->validateConfigurationForm($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $link = $form['#plugin_form']->submitConfigurationForm($form, $form_state);
 
     drupal_set_message($this->t('The menu link has been saved.'));
diff --git a/core/modules/menu_ui/src/Form/MenuLinkResetForm.php b/core/modules/menu_ui/src/Form/MenuLinkResetForm.php
index b5663aa..09cfb87 100644
--- a/core/modules/menu_ui/src/Form/MenuLinkResetForm.php
+++ b/core/modules/menu_ui/src/Form/MenuLinkResetForm.php
@@ -7,19 +7,64 @@
 
 namespace Drupal\menu_ui\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Menu\MenuLinkManagerInterface;
+use Drupal\Core\Menu\MenuLinkInterface;
+use Drupal\Core\Routing\Access\AccessInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Defines a confirmation form for resetting a single modified menu link.
  */
-class MenuLinkResetForm extends EntityConfirmFormBase {
+class MenuLinkResetForm extends ConfirmFormBase {
+
+  /**
+   * The menu link manager.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
+   */
+  protected $menuLinkManager;
+
+  /**
+   * The menu link.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkInterface
+   */
+  protected $link;
+
+  /**
+   * Constructs a MenuLinkResetForm object.
+   *
+   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
+   *   The menu link manager.
+   */
+  public function __construct(MenuLinkManagerInterface $menu_link_manager) {
+    $this->menuLinkManager = $menu_link_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.menu.link')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'menu_link_reset_confirm';
+  }
 
   /**
    * {@inheritdoc}
    */
   public function getQuestion() {
-    return t('Are you sure you want to reset the link %item to its default values?', array('%item' => $this->entity->link_title));
+    return $this->t('Are you sure you want to reset the link %item to its default values?', array('%item' => $this->link->getTitle()));
   }
 
   /**
@@ -27,7 +72,7 @@ public function getQuestion() {
    */
   public function getCancelUrl() {
     return new Url('menu_ui.menu_edit', array(
-      'menu' => $this->entity->menu_name,
+      'menu' => $this->link->getMenuName(),
     ));
   }
 
@@ -35,23 +80,47 @@ public function getCancelUrl() {
    * {@inheritdoc}
    */
   public function getDescription() {
-    return t('Any customizations will be lost. This action cannot be undone.');
+    return $this->t('Any customizations will be lost. This action cannot be undone.');
   }
 
   /**
    * {@inheritdoc}
    */
   public function getConfirmText() {
-    return t('Reset');
+    return $this->t('Reset');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
-    $this->entity = $this->entity->reset();
-    drupal_set_message(t('The menu link was reset to its default settings.'));
+  public function buildForm(array $form, FormStateInterface $form_state, MenuLinkInterface $menu_link_plugin = NULL) {
+    $this->link = $menu_link_plugin;
+
+    $form = parent::buildForm($form, $form_state);
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $this->link = $this->menuLinkManager->resetLink($this->link->getPluginId());
+    drupal_set_message($this->t('The menu link was reset to its default settings.'));
     $form_state['redirect_route'] = $this->getCancelUrl();
   }
 
+  /**
+   * Checks access based on whether the link can be reset.
+   *
+   * @param \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin
+   *   The menu link plugin being checked.
+   *
+   * @return string
+   *   AccessInterface::ALLOW when access was granted, otherwise
+   *   AccessInterface::DENY.
+   */
+  public function linkIsResettable(MenuLinkInterface $menu_link_plugin) {
+    return $menu_link_plugin->isResettable() ? AccessInterface::ALLOW : AccessInterface::DENY;
+  }
+
 }
diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php
index d854f3c..d115736 100644
--- a/core/modules/menu_ui/src/MenuForm.php
+++ b/core/modules/menu_ui/src/MenuForm.php
@@ -10,10 +10,15 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Menu\MenuLinkManagerInterface;
+use Drupal\Core\Menu\MenuLinkTreeElement;
+use Drupal\Core\Menu\MenuLinkTreeInterface;
+use Drupal\Core\Menu\MenuTreeParameters;
 use Drupal\Core\Render\Element;
-use Drupal\menu_link\MenuLinkStorageInterface;
-use Drupal\menu_link\MenuTreeInterface;
+use Drupal\Core\Routing\UrlGeneratorTrait;
+use Drupal\Core\Utility\LinkGeneratorInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -29,20 +34,27 @@ class MenuForm extends EntityForm {
   protected $entityQueryFactory;
 
   /**
-   * The menu link storage.
+   * The menu link manager.
    *
-   * @var \Drupal\menu_link\MenuLinkStorageInterface
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
    */
-  protected $menuLinkStorage;
+  protected $menuLinkManager;
 
   /**
    * The menu tree service.
    *
-   * @var \Drupal\menu_link\MenuTreeInterface
+   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
    */
   protected $menuTree;
 
   /**
+   * The link generator.
+   *
+   * @var \Drupal\Core\Utility\LinkGeneratorInterface
+   */
+  protected $linkGenerator;
+
+  /**
    * The overview tree form.
    *
    * @var array
@@ -54,15 +66,18 @@ class MenuForm extends EntityForm {
    *
    * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
    *   The factory for entity queries.
-   * @param \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage
-   *   The menu link storage.
-   * @param \Drupal\menu_link\MenuTreeInterface $menu_tree
+   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
+   *   The menu link manager.
+   * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
    *   The menu tree service.
+   * @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
+   *   The link generator.
    */
-  public function __construct(QueryFactory $entity_query_factory, MenuLinkStorageInterface $menu_link_storage, MenuTreeInterface $menu_tree) {
+  public function __construct(QueryFactory $entity_query_factory, MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator) {
     $this->entityQueryFactory = $entity_query_factory;
-    $this->menuLinkStorage = $menu_link_storage;
+    $this->menuLinkManager = $menu_link_manager;
     $this->menuTree = $menu_tree;
+    $this->linkGenerator = $link_generator;
   }
 
   /**
@@ -71,15 +86,16 @@ public function __construct(QueryFactory $entity_query_factory, MenuLinkStorageI
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.query'),
-      $container->get('entity.manager')->getStorage('menu_link'),
-      $container->get('menu_link.tree')
+      $container->get('plugin.manager.menu.link'),
+      $container->get('menu.link_tree'),
+      $container->get('link_generator')
     );
   }
 
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $menu = $this->entity;
 
     if ($this->operation == 'edit') {
@@ -88,16 +104,16 @@ public function form(array $form, array &$form_state) {
 
     $form['label'] = array(
       '#type' => 'textfield',
-      '#title' => t('Title'),
+      '#title' => $this->t('Title'),
       '#default_value' => $menu->label(),
       '#required' => TRUE,
     );
     $form['id'] = array(
       '#type' => 'machine_name',
-      '#title' => t('Menu name'),
+      '#title' => $this->t('Menu name'),
       '#default_value' => $menu->id(),
       '#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI,
-      '#description' => t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'),
+      '#description' => $this->t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'),
       '#machine_name' => array(
         'exists' => array($this, 'menuNameExists'),
         'source' => array('label'),
@@ -120,28 +136,11 @@ public function form(array $form, array &$form_state) {
       '#languages' => LanguageInterface::STATE_ALL,
       '#default_value' => $menu->language()->getId(),
     );
-    // Unlike the menu langcode, the default language configuration for menu
-    // links only works with language module installed.
-    if ($this->moduleHandler->moduleExists('language')) {
-      $form['default_menu_links_language'] = array(
-        '#type' => 'details',
-        '#title' => t('Menu links language'),
-        '#open' => TRUE,
-      );
-      $form['default_menu_links_language']['default_language'] = array(
-        '#type' => 'language_configuration',
-        '#entity_information' => array(
-          'entity_type' => 'menu_link',
-          'bundle' => $menu->id(),
-        ),
-        '#default_value' => language_get_default_configuration('menu_link', $menu->id()),
-      );
-    }
 
     // Add menu links administration form for existing menus.
     if (!$menu->isNew() || $menu->isLocked()) {
       // Form API supports constructing and validating self-contained sections
-      // within forms, but does not allow to handle the form section's submission
+      // within forms, but does not allow handling the form section's submission
       // equally separated yet. Therefore, we use a $form_state key to point to
       // the parents of the form section.
       // @see self::submitOverviewForm()
@@ -169,47 +168,13 @@ public function menuNameExists($value) {
     }
 
     // Check for a link assigned to this menu.
-    return $this->entityQueryFactory->get('menu_link')->condition('menu_name', $value)->range(0, 1)->count()->execute();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function actions(array $form, array &$form_state) {
-    $actions = parent::actions($form, $form_state);
-
-    // Add the language configuration submit handler. This is needed because the
-    // submit button has custom submit handlers.
-    if ($this->moduleHandler->moduleExists('language')) {
-      array_unshift($actions['submit']['#submit'],'language_configuration_element_submit');
-      array_unshift($actions['submit']['#submit'], array($this, 'languageConfigurationSubmit'));
-    }
-    // We cannot leverage the regular submit handler definition because we have
-    // button-specific ones here. Hence we need to explicitly set it for the
-    // submit action, otherwise it would be ignored.
-    if ($this->moduleHandler->moduleExists('content_translation')) {
-      array_unshift($actions['submit']['#submit'], 'content_translation_language_configuration_element_submit');
-    }
-    return $actions;
-  }
-
-  /**
-   * Submit handler to update the bundle for the default language configuration.
-   */
-  public function languageConfigurationSubmit(array &$form, array &$form_state) {
-    // Since the machine name is not known yet, and it can be changed anytime,
-    // we have to also update the bundle property for the default language
-    // configuration in order to have the correct bundle value.
-    $form_state['language']['default_language']['bundle'] = $form_state['values']['id'];
-    // Clear cache so new menus (bundles) show on the language settings admin
-    // page.
-    \Drupal::entityManager()->clearCachedBundles();
+    return $this->menuLinkManager->menuNameInUse($value);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $menu = $this->entity;
     if (!$menu->isNew() || $menu->isLocked()) {
       $this->submitOverviewForm($form, $form_state);
@@ -217,13 +182,13 @@ public function save(array $form, array &$form_state) {
 
     $status = $menu->save();
 
-    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+    $edit_link = $this->linkGenerator->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
     if ($status == SAVED_UPDATED) {
-      drupal_set_message(t('Menu %label has been updated.', array('%label' => $menu->label())));
+      drupal_set_message($this->t('Menu %label has been updated.', array('%label' => $menu->label())));
       watchdog('menu', 'Menu %label has been updated.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
     }
     else {
-      drupal_set_message(t('Menu %label has been added.', array('%label' => $menu->label())));
+      drupal_set_message($this->t('Menu %label has been added.', array('%label' => $menu->label())));
       watchdog('menu', 'Menu %label has been added.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
     }
 
@@ -244,35 +209,39 @@ public function save(array $form, array &$form_state) {
    * Forms integrating this section should call menu_overview_form_submit() from
    * their form submit handler.
    */
-  protected function buildOverviewForm(array &$form, array &$form_state) {
+  protected function buildOverviewForm(array &$form, FormStateInterface $form_state) {
     // Ensure that menu_overview_form_submit() knows the parents of this form
     // section.
     $form['#tree'] = TRUE;
     $form['#theme'] = 'menu_overview_form';
-    $form_state += array('menu_overview_form_parents' => array());
+    $form_state->setIfNotExists('menu_overview_form_parents', array());
 
     $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/css/menu.admin.css');
 
-    $links = array();
-    $query = $this->entityQueryFactory->get('menu_link')
-      ->condition('menu_name', $this->entity->id());
-    for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
-      $query->sort('p' . $i, 'ASC');
-    }
-    $result = $query->execute();
+    $tree = $this->menuTree->load($this->entity->id(), new MenuTreeParameters());
 
-    if (!empty($result)) {
-      $links = $this->menuLinkStorage->loadMultiple($result);
-    }
-
-    $delta = max(count($links), 50);
     // We indicate that a menu administrator is running the menu access check.
     $this->getRequest()->attributes->set('_menu_admin', TRUE);
-    $tree = $this->menuTree->buildTreeData($links);
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+      array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    );
+    $tree = $this->menuTree->transform($tree, $manipulators);
     $this->getRequest()->attributes->set('_menu_admin', FALSE);
 
+    // Determine the delta; the number of weights to be made available.
+    $count = function(array $tree) {
+      $sum = function ($carry, MenuLinkTreeElement $item) {
+        return $carry + $item->count();
+      };
+      return array_reduce($tree, $sum);
+    };
+    $delta = max($count($tree), 50);
+
     $form = array_merge($form, $this->buildOverviewTreeForm($tree, $delta));
-    $form['#empty_text'] = t('There are no menu links yet. <a href="@link">Add link</a>.', array('@link' => url('admin/structure/menu/manage/' . $this->entity->id() .'/add')));
+    $destination = $this->getUrlGenerator()->getPathFromRoute('menu_ui.menu_edit', array('menu' => $this->entity->id()));
+    $url = $destination = $this->url('menu_link_content.link_add', array('menu' => $this->entity->id()), array('query' => array('destination' => $destination)));
+    $form['#empty_text'] = $this->t('There are no menu links yet. <a href="@url">Add link</a>.', array('@url' => $url));
 
     return $form;
   }
@@ -281,7 +250,7 @@ protected function buildOverviewForm(array &$form, array &$form_state) {
    * Recursive helper function for buildOverviewForm().
    *
    * @param $tree
-   *   The menu_tree retrieved by menu_tree_data.
+   *   The tree retrieved by \Drupal\Core\Menu\MenuLinkTreeInterface::load().
    * @param $delta
    *   The default number of menu items used in the menu weight selector is 50.
    *
@@ -290,70 +259,87 @@ protected function buildOverviewForm(array &$form, array &$form_state) {
    */
   protected function buildOverviewTreeForm($tree, $delta) {
     $form = &$this->overviewTreeForm;
-    foreach ($tree as $data) {
-      $item = $data['link'];
-      // Don't show callbacks; these have $item['hidden'] < 0.
-      if ($item && $item['hidden'] >= 0) {
-        $mlid = 'mlid:' . $item['mlid'];
-        $form[$mlid]['#item'] = $item;
-        $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled'));
-        $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']);
-        if ($item['hidden']) {
-          $form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')';
+    foreach ($tree as $element) {
+      /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
+      $link = $element->link;
+      if ($link) {
+        $id = 'menu_plugin_id:' . $link->getPluginId();
+        $form[$id]['#item'] = $element;
+        $form[$id]['#attributes'] = $link->isHidden() ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled'));
+        $form[$id]['title']['#markup'] = $this->linkGenerator->generateFromUrl($link->getTitle(), $link->getUrlObject(), $link->getOptions());
+        if ($link->isHidden()) {
+          $form[$id]['title']['#markup'] .= ' (' . $this->t('disabled') . ')';
         }
-        elseif ($item['link_path'] == 'user' && $item['module'] == 'user') {
-          $form[$mlid]['title']['#markup'] .= ' (' . t('logged in users only') . ')';
+        elseif (($url = $link->getUrlObject()) && !$url->isExternal() && $url->getRouteName() == 'user.page') {
+          $form[$id]['title']['#markup'] .= ' (' . $this->t('logged in users only') . ')';
         }
 
-        $form[$mlid]['hidden'] = array(
+        $form[$id]['enabled'] = array(
           '#type' => 'checkbox',
-          '#title' => t('Enable @title menu link', array('@title' => $item['title'])),
+          '#title' => $this->t('Enable @title menu link', array('@title' => $link->getTitle())),
           '#title_display' => 'invisible',
-          '#default_value' => !$item['hidden'],
+          '#default_value' => !$link->isHidden(),
         );
-        $form[$mlid]['weight'] = array(
+        $form[$id]['weight'] = array(
           '#type' => 'weight',
           '#delta' => $delta,
-          '#default_value' => $item['weight'],
-          '#title' => t('Weight for @title', array('@title' => $item['title'])),
+          '#default_value' => $link->getWeight(),
+          '#title' => $this->t('Weight for @title', array('@title' => $link->getTitle())),
           '#title_display' => 'invisible',
         );
-        $form[$mlid]['mlid'] = array(
+        $form[$id]['id'] = array(
           '#type' => 'hidden',
-          '#value' => $item['mlid'],
+          '#value' => $link->getPluginId(),
         );
-        $form[$mlid]['plid'] = array(
+        $form[$id]['parent'] = array(
           '#type' => 'hidden',
-          '#default_value' => $item['plid'],
+          '#default_value' => $link->getParent(),
         );
         // Build a list of operations.
         $operations = array();
         $operations['edit'] = array(
-          'title' => t('Edit'),
-          'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/edit',
+          'title' => $this->t('Edit'),
         );
-        // Only items created by the Menu UI module can be deleted.
-        if ($item->access('delete')) {
-          $operations['delete'] = array(
-            'title' => t('Delete'),
-            'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/delete',
+        // Allow for a custom edit link per plugin.
+        $edit_route = $link->getEditRoute();
+        if ($edit_route) {
+          $operations['edit'] += $edit_route;
+          // Bring the user back to the menu overview.
+          $operations['edit']['query']['destination'] = $this->entity->url();
+        }
+        else {
+          // Fall back to the standard edit link.
+          $operations['edit'] += array(
+            'route_name' => 'menu_ui.link_edit',
+            'route_parameters' => array('menu_link_plugin' => $link->getPluginId()),
           );
         }
-        // Set the reset column.
-        elseif ($item->access('reset')) {
+        // Links can either be reset or deleted, not both.
+        if ($link->isResettable()) {
           $operations['reset'] = array(
-            'title' => t('Reset'),
-            'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/reset',
+            'title' => $this->t('Reset'),
+            'route_name' => 'menu_ui.link_reset',
+            'route_parameters' => array('menu_link_plugin' => $link->getPluginId()),
           );
         }
-        $form[$mlid]['operations'] = array(
+        elseif ($delete_link = $link->getDeleteRoute()) {
+          $operations['delete'] = $delete_link;
+          $operations['delete']['query']['destination'] = $this->entity->url();
+          $operations['delete']['title'] = $this->t('Delete');
+        }
+        if ($link->isTranslatable()) {
+          $operations['translate'] = array(
+            'title' => $this->t('Translate'),
+          ) + (array) $link->getTranslateRoute();
+        }
+        $form[$id]['operations'] = array(
           '#type' => 'operations',
           '#links' => $operations,
         );
       }
 
-      if ($data['below']) {
-        $this->buildOverviewTreeForm($data['below'], $delta);
+      if ($element->subtree) {
+        $this->buildOverviewTreeForm($element->subtree, $delta);
       }
     }
     return $form;
@@ -363,9 +349,9 @@ protected function buildOverviewTreeForm($tree, $delta) {
    * Submit handler for the menu overview form.
    *
    * This function takes great care in saving parent items first, then items
-   * underneath them. Saving items in the incorrect order can break the menu tree.
+   * underneath them. Saving items in the incorrect order can break the tree.
    */
-  protected function submitOverviewForm(array $complete_form, array &$form_state) {
+  protected function submitOverviewForm(array $complete_form, FormStateInterface $form_state) {
     // Form API supports constructing and validating self-contained sections
     // within forms, but does not allow to handle the form section's submission
     // equally separated yet. Therefore, we use a $form_state key to point to
@@ -384,32 +370,30 @@ protected function submitOverviewForm(array $complete_form, array &$form_state)
     // Update our original form with the new order.
     $form = array_intersect_key(array_merge($order, $form), $form);
 
-    $updated_items = array();
-    $fields = array('weight', 'plid');
-    foreach (Element::children($form) as $mlid) {
-      if (isset($form[$mlid]['#item'])) {
-        $element = $form[$mlid];
+    $fields = array('weight', 'parent', 'enabled');
+    foreach (Element::children($form) as $id) {
+      if (isset($form[$id]['#item'])) {
+        $element = $form[$id];
+        $updated_values = array();
         // Update any fields that have changed in this menu item.
         foreach ($fields as $field) {
           if ($element[$field]['#value'] != $element[$field]['#default_value']) {
-            $element['#item'][$field] = $element[$field]['#value'];
-            $updated_items[$mlid] = $element['#item'];
+            // Hidden is a special case, the form value needs to be reversed.
+            if ($field == 'enabled') {
+              $updated_values['hidden'] = $element['enabled']['#value'] ? 0 : 1;
+            }
+            else {
+              $updated_values[$field] = $element[$field]['#value'];
+            }
           }
         }
-        // Hidden is a special case, the value needs to be reversed.
-        if ($element['hidden']['#value'] != $element['hidden']['#default_value']) {
-          // Convert to integer rather than boolean due to PDO cast to string.
-          $element['#item']['hidden'] = $element['hidden']['#value'] ? 0 : 1;
-          $updated_items[$mlid] = $element['#item'];
+        if ($updated_values) {
+          // Use the ID from the actual plugin instance since the hidden value
+          // in the form could be tampered with.
+          $this->menuLinkManager->updateDefinition($element['#item']->link->getPLuginId(), $updated_values);
         }
       }
     }
-
-    // Save all our changed items to the database.
-    foreach ($updated_items as $item) {
-      $item['customized'] = 1;
-      $item->save();
-    }
   }
 
 }
diff --git a/core/modules/menu_ui/src/MenuSettingsForm.php b/core/modules/menu_ui/src/MenuSettingsForm.php
index 73bc7d7..77c3c15 100644
--- a/core/modules/menu_ui/src/MenuSettingsForm.php
+++ b/core/modules/menu_ui/src/MenuSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\menu_ui;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Select the menus to be used for the main and secondary links for this site.
@@ -22,9 +23,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('menu_ui.settings');
     $form['intro'] = array(
       '#type' => 'item',
@@ -58,9 +59,9 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('menu_ui.settings')
       ->set('main_links', $form_state['values']['menu_main_links_source'])
       ->set('secondary_links', $form_state['values']['menu_secondary_links_source'])
diff --git a/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php b/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php
new file mode 100644
index 0000000..9fee161
--- /dev/null
+++ b/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd.
+ */
+
+namespace Drupal\menu_ui\Plugin\Menu\LocalAction;
+
+use Drupal\Core\Menu\LocalActionDefault;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Modifies the 'Add link' local action to add a destination.
+ */
+class MenuLinkAdd extends LocalActionDefault {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOptions(Request $request) {
+    $options = parent::getOptions($request);
+    // Append the current path as destination to the query string.
+    if ($request->attributes->has(RouteObjectInterface::ROUTE_NAME)) {
+      $route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
+      $raw_variables = array();
+      if ($request->attributes->has('_raw_variables')) {
+        $raw_variables = $request->attributes->get('_raw_variables')->all();
+      }
+      // @todo Use RouteMatch instead of Request.
+      //   https://www.drupal.org/node/2294157
+      $options['query']['destination'] = \Drupal::urlGenerator()->generateFromRoute($route_name, $raw_variables);
+    }
+    return $options;
+  }
+
+}
diff --git a/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php b/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
index c863b8d..4a19182 100644
--- a/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\menu\Tests\MenuCacheTagsTest.
+ * Contains \Drupal\menu_ui\Tests\MenuCacheTagsTest.
  */
 
 namespace Drupal\menu_ui\Tests;
@@ -37,12 +37,10 @@ public function testMenuBlock() {
       'description' => 'Description text',
     ));
     $menu->save();
-    $menu_link = entity_create('menu_link', array(
-      'link_path' => '<front>',
-      'link_title' => 'Vicuña',
-      'menu_name' => 'llama',
-    ));
-    $menu_link->save();
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    // Move a link into the new menu.
+    $menu_link = $menu_link_manager->updateDefinition('test_page_test.test_page', array('menu_name' => 'llama', 'parent' => ''));
     $block = $this->drupalPlaceBlock('system_menu_block:llama', array('label' => 'Llama', 'provider' => 'system', 'region' => 'footer'));
 
     // Prime the page cache.
@@ -60,7 +58,6 @@ public function testMenuBlock() {
     );
     $this->verifyPageCache($path, 'HIT', $expected_tags);
 
-
     // Verify that after modifying the menu, there is a cache miss.
     $this->pass('Test modification of menu.', 'Debug');
     $menu->label = 'Awesome llama';
@@ -70,23 +67,23 @@ public function testMenuBlock() {
     // Verify a cache hit.
     $this->verifyPageCache($path, 'HIT');
 
-
-    // Verify that after modifying the menu link, there is a cache miss.
+    // Verify that after modifying the menu link weight, there is a cache miss.
+    $menu_link_manager->updateDefinition('test_page_test.test_page', array('weight' => -10));
     $this->pass('Test modification of menu link.', 'Debug');
-    $menu_link->link_title = 'Guanaco';
-    $menu_link->save();
     $this->verifyPageCache($path, 'MISS');
 
     // Verify a cache hit.
     $this->verifyPageCache($path, 'HIT');
 
-
     // Verify that after adding a menu link, there is a cache miss.
     $this->pass('Test addition of menu link.', 'Debug');
-    $menu_link_2 = entity_create('menu_link', array(
-      'link_path' => '<front>',
-      'link_title' => 'Alpaca',
+    $menu_link_2 = entity_create('menu_link_content', array(
+      'id' => '',
+      'parent' => '',
+      'title' => 'Alpaca',
       'menu_name' => 'llama',
+      'route_name' => '<front>',
+      'bundle' => 'menu_name',
     ));
     $menu_link_2->save();
     $this->verifyPageCache($path, 'MISS');
@@ -94,16 +91,15 @@ public function testMenuBlock() {
     // Verify a cache hit.
     $this->verifyPageCache($path, 'HIT');
 
-
-    // Verify that after deleting the first menu link, there is a cache miss.
-    $this->pass('Test deletion of menu link.', 'Debug');
-    $menu_link->delete();
+    // Verify that after resetting the first menu link, there is a cache miss.
+    $this->pass('Test reset of menu link.', 'Debug');
+    $this->assertTrue($menu_link->isResettable(), 'First link can be reset');
+    $menu_link = $menu_link_manager->resetLink($menu_link->getPluginId());
     $this->verifyPageCache($path, 'MISS');
 
     // Verify a cache hit.
     $this->verifyPageCache($path, 'HIT', $expected_tags);
 
-
     // Verify that after deleting the menu, there is a cache miss.
     $this->pass('Test deletion of menu.', 'Debug');
     $menu->delete();
diff --git a/core/modules/menu_ui/src/Tests/MenuLanguageTest.php b/core/modules/menu_ui/src/Tests/MenuLanguageTest.php
index 9267c28..88d9150 100644
--- a/core/modules/menu_ui/src/Tests/MenuLanguageTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuLanguageTest.php
@@ -59,21 +59,12 @@ function testMenuLanguage() {
       'description' => '',
       'label' =>  $label,
       'langcode' => 'aa',
-      'default_language[langcode]' => 'bb',
-      'default_language[language_show]' => TRUE,
     );
     $this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
+    language_save_default_configuration('menu_link_content', 'menu_link_content',  array('langcode' => 'bb', 'language_show' => TRUE));
 
-    // Check that the language settings were saved.
-    $this->assertEqual(entity_load('menu', $menu_name)->language()->getId(), $edit['langcode']);
-    $language_settings = language_get_default_configuration('menu_link', $menu_name);
-    $this->assertEqual($language_settings['langcode'], 'bb');
-    $this->assertEqual($language_settings['language_show'], TRUE);
-
-    // Check menu language and item language configuration.
+    // Check menu language.
     $this->assertOptionSelected('edit-langcode', $edit['langcode'], 'The menu language was correctly selected.');
-    $this->assertOptionSelected('edit-default-language-langcode', $edit['default_language[langcode]'], 'The menu link default language was correctly selected.');
-    $this->assertFieldChecked('edit-default-language-language-show');
 
     // Test menu link language.
     $link_path = '<front>';
@@ -81,41 +72,35 @@ function testMenuLanguage() {
     // Add a menu link.
     $link_title = $this->randomString();
     $edit = array(
-      'link_title' => $link_title,
-      'link_path' => $link_path,
+      'title[0][value]' => $link_title,
+      'url' => $link_path,
     );
     $this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
     // Check the link was added with the correct menu link default language.
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $link_title));
+    $menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $link_title));
     $menu_link = reset($menu_links);
-    $this->assertMenuLink($menu_link->id(), array(
+    $this->assertMenuLink($menu_link->getPluginId(), array(
       'menu_name' => $menu_name,
-      'link_path' => $link_path,
+      'route_name' => '<front>',
       'langcode' => 'bb',
     ));
 
     // Edit menu link default, changing it to cc.
-    $edit = array(
-      'default_language[langcode]' => 'cc',
-    );
-    $this->drupalPostForm("admin/structure/menu/manage/$menu_name", $edit, t('Save'));
-
-    // Check cc is the menu link default.
-    $this->assertOptionSelected('edit-default-language-langcode', $edit['default_language[langcode]'], 'The menu link default language was correctly selected.');
+    language_save_default_configuration('menu_link_content', 'menu_link_content',  array('langcode' => 'cc', 'language_show' => TRUE));
 
     // Add a menu link.
     $link_title = $this->randomString();
     $edit = array(
-      'link_title' => $link_title,
-      'link_path' => $link_path,
+      'title[0][value]' => $link_title,
+      'url' => $link_path,
     );
     $this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
     // Check the link was added with the correct new menu link default language.
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $link_title));
+    $menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $link_title));
     $menu_link = reset($menu_links);
-    $this->assertMenuLink($menu_link->id(), array(
+    $this->assertMenuLink($menu_link->getPluginId(), array(
       'menu_name' => $menu_name,
-      'link_path' => $link_path,
+      'route_name' => '<front>',
       'langcode' => 'cc',
     ));
 
@@ -124,9 +109,9 @@ function testMenuLanguage() {
       'langcode' => 'bb',
     );
     $this->drupalPostForm('admin/structure/menu/item/' . $menu_link->id() . '/edit', $edit, t('Save'));
-    $this->assertMenuLink($menu_link->id(), array(
+    $this->assertMenuLink($menu_link->getPluginId(), array(
       'menu_name' => $menu_name,
-      'link_path' => $link_path,
+      'route_name' => '<front>',
       'langcode' => 'bb',
     ));
 
@@ -138,16 +123,7 @@ function testMenuLanguage() {
     $this->assertOptionSelected('edit-langcode', 'bb', 'The menu link language was correctly selected.');
 
     // Edit menu to hide the language select on menu link item add.
-    $edit = array(
-      'default_language[language_show]' => FALSE,
-    );
-    $this->drupalPostForm("admin/structure/menu/manage/$menu_name", $edit, t('Save'));
-    $this->assertNoFieldChecked('edit-default-language-language-show');
-
-    // Check that the language settings were saved.
-    $language_settings = language_get_default_configuration('menu_link', $menu_name);
-    $this->assertEqual($language_settings['langcode'], 'cc');
-    $this->assertEqual($language_settings['language_show'], FALSE);
+     language_save_default_configuration('menu_link_content', 'menu_link_content',  array('langcode' => 'cc', 'language_show' => FALSE));
 
     // Check that the language selector is not available on menu link add page.
     $this->drupalGet("admin/structure/menu/manage/$menu_name/add");
diff --git a/core/modules/menu_ui/src/Tests/MenuNodeTest.php b/core/modules/menu_ui/src/Tests/MenuNodeTest.php
index 819bd56..7251397 100644
--- a/core/modules/menu_ui/src/Tests/MenuNodeTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuNodeTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Definition of Drupal\menu_ui\Tests\MenuNodeTest.
+ * Contains \Drupal\menu_ui\Tests\MenuNodeTest.
  */
 
 namespace Drupal\menu_ui\Tests;
@@ -65,7 +65,7 @@ function testMenuNodeFormWidget() {
     $edit = array(
       'menu_options[main]' => 1,
       'menu_options[tools]' => 1,
-      'menu_parent' => 'main:0',
+      'menu_parent' => 'main:',
     );
     $this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
 
@@ -93,7 +93,7 @@ function testMenuNodeFormWidget() {
     // Edit the node and create a menu link.
     $edit = array(
       'menu[enabled]' => 1,
-      'menu[link_title]' => $node_title,
+      'menu[title]' => $node_title,
       'menu[weight]' => 17,
     );
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
@@ -102,7 +102,7 @@ function testMenuNodeFormWidget() {
     $this->assertLink($node_title);
 
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertOptionSelected('edit-menu-weight', 17, 'Menu weight correct in edit form');
+    $this->assertFieldById('edit-menu-weight', 17, 'Menu weight correct in edit form');
 
     // Edit the node and remove the menu link.
     $edit = array(
@@ -114,10 +114,12 @@ function testMenuNodeFormWidget() {
     $this->assertNoLink($node_title);
 
     // Add a menu link to the Administration menu.
-    $item = entity_create('menu_link', array(
-      'link_path' => 'node/' . $node->id(),
-      'link_title' => $this->randomName(16),
+    $item = entity_create('menu_link_content', array(
+      'route_name' => 'node.view',
+      'route_parameters' => array('node' => $node->id()),
+      'title' => $this->randomName(16),
       'menu_name' => 'admin',
+      'bundle' => 'menu_link_content',
     ));
     $item->save();
 
@@ -127,27 +129,30 @@ function testMenuNodeFormWidget() {
     $this->assertText('Provide a menu link', 'Link in not allowed menu not shown in node edit form');
     // Assert that the link is still in the Administration menu after save.
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
-    $link = menu_link_load($item['mlid']);
+    $link = entity_load('menu_link_content', $item->id());
     $this->assertTrue($link, 'Link in not allowed menu still exists after saving node');
 
     // Move the menu link back to the Tools menu.
-    $item['menu_name'] = 'tools';
-    menu_link_save($item);
+    $item->menu_name->value = 'tools';
+    $item->save();
     // Create a second node.
     $child_node = $this->drupalCreateNode(array('type' => 'article'));
     // Assign a menu link to the second node, being a child of the first one.
-    $child_item = entity_create('menu_link', array(
-      'link_path' => 'node/'. $child_node->id(),
-      'link_title' => $this->randomName(16),
-      'plid' => $item['mlid'],
+    $child_item = entity_create('menu_link_content', array(
+      'route_name' => 'node.view',
+      'route_parameters' => array('node' => $child_node->id()),
+      'title' => $this->randomName(16),
+      'parent' => $item->getPluginId(),
+      'menu_name' => $item->getMenuName(),
+      'bundle' => 'menu_link_content',
     ));
     $child_item->save();
     // Edit the first node.
     $this->drupalGet('node/'. $node->id() .'/edit');
     // Assert that it is not possible to set the parent of the first node to itself or the second node.
-    $this->assertNoOption('edit-menu-parent', 'tools:'. $item['mlid']);
-    $this->assertNoOption('edit-menu-parent', 'tools:'. $child_item['mlid']);
+    $this->assertNoOption('edit-menu-menu-parent', 'tools:'. $item->getPluginId());
+    $this->assertNoOption('edit-menu-menu-parent', 'tools:'. $child_item->getPluginId());
     // Assert that unallowed Administration menu is not available in options.
-    $this->assertNoOption('edit-menu-parent', 'admin:0');
+    $this->assertNoOption('edit-menu-menu-parent', 'admin:');
   }
 }
diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php
index f707eb9..8a10db7 100644
--- a/core/modules/menu_ui/src/Tests/MenuTest.php
+++ b/core/modules/menu_ui/src/Tests/MenuTest.php
@@ -2,12 +2,14 @@
 
 /**
  * @file
- * Definition of Drupal\menu_ui\Tests\MenuTest.
+ * Contains \Drupal\menu_ui\Tests\MenuTest.
  */
 
 namespace Drupal\menu_ui\Tests;
 
 use Drupal\Component\Serialization\Json;
+use Drupal\Core\Menu\MenuLinkInterface;
+use Drupal\menu_link_content\Entity\MenuLinkContent;
 use Drupal\system\Entity\Menu;
 
 /**
@@ -49,7 +51,7 @@ class MenuTest extends MenuWebTestBase {
   /**
    * An array of test menu links.
    *
-   * @var array
+   * @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface[]
    */
   protected $items;
 
@@ -78,17 +80,20 @@ function testMenu() {
 
     // Verify that the menu links rebuild is idempotent and leaves the same
     // number of links in the table.
-    $before_count = db_query('SELECT COUNT(*) FROM {menu_links}')->fetchField();
-    menu_link_rebuild_defaults();
-    $after_count = db_query('SELECT COUNT(*) FROM {menu_links}')->fetchField();
-    $this->assertIdentical($before_count, $after_count, 'menu_link_rebuild_defaults() does not add more links');
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $before_count = $menu_link_manager->countMenuLinks(NULL);
+    $menu_link_manager->rebuild();
+    $after_count = $menu_link_manager->countMenuLinks(NULL);
+    $this->assertIdentical($before_count, $after_count, 'MenuLinkManager::rebuild() does not add more links');
     // Do standard user tests.
     // Login the user.
     $this->drupalLogin($this->authenticated_user);
     $this->verifyAccess(403);
+
     foreach ($this->items as $item) {
       // Paths were set as 'node/$nid'.
-      $node = node_load(substr($item['link_path'], 5));
+      $node = node_load($item->getRouteParameters()['node']);
       $this->verifyMenuLink($item, $node);
     }
 
@@ -104,20 +109,20 @@ function testMenu() {
     $this->deleteCustomMenu();
 
     // Modify and reset a standard menu link.
-    $item = $this->getStandardMenuLink();
-    $old_title = $item['link_title'];
-    $this->modifyMenuLink($item);
-    $item = entity_load('menu_link', $item['mlid']);
-    // Verify that a change to the description is saved.
-    $description = $this->randomName(16);
-    $item['options']['attributes']['title']  = $description;
-    $return_value = menu_link_save($item);
-    // Save the menu link again to test the return value of the procedural save
-    // helper.
-    $this->assertIdentical($return_value, $item->save(), 'Return value of menu_link_save() is identical to the return value of $menu_link->save().');
-    $saved_item = entity_load('menu_link', $item['mlid']);
-    $this->assertEqual($description, $saved_item['options']['attributes']['title'], 'Saving an existing link updates the description (title attribute)');
-    $this->resetMenuLink($item, $old_title);
+    $instance = $this->getStandardMenuLink();
+    $old_weight = $instance->getWeight();
+    // Edit the static menu link.
+    $edit = array();
+    $edit['weight'] = 10;
+    $id = $instance->getPluginId();
+    $this->drupalPostForm("admin/structure/menu/link/$id/edit", $edit, t('Save'));
+    $this->assertResponse(200);
+    $this->assertText('The menu link has been saved.');
+    $menu_link_manager->resetDefinitions();
+
+    $instance = $menu_link_manager->createInstance($instance->getPluginId());
+    $this->assertEqual($edit['weight'], $instance->getWeight(), 'Saving an existing link updates the weight.');
+    $this->resetMenuLink($instance, $old_weight);
   }
 
   /**
@@ -214,7 +219,7 @@ function deleteCustomMenu() {
     $this->assertRaw(t('The custom menu %title has been deleted.', array('%title' => $label)), 'Custom menu was deleted');
     $this->assertNull(Menu::load($menu_name), 'Custom menu was deleted');
     // Test if all menu links associated to the menu were removed from database.
-    $result = entity_load_multiple_by_properties('menu_link', array('menu_name' => $menu_name));
+    $result = entity_load_multiple_by_properties('menu_link_content', array('menu_name' => $menu_name));
     $this->assertFalse($result, 'All menu links associated to the custom menu were deleted.');
 
     // Make sure there's no delete button on system menus.
@@ -244,34 +249,37 @@ function doMenuTests() {
       ),
     ));
 
+    // Verify add link button.
+    $this->drupalGet('admin/structure/menu');
+    $this->assertLinkByHref('admin/structure/menu/manage/' . $menu_name . '/add', "The add menu link button url is correct");
+
     // Add menu links.
-    $item1 = $this->addMenuLink(0, 'node/' . $node1->id(), $menu_name);
-    $item2 = $this->addMenuLink($item1['mlid'], 'node/' . $node2->id(), $menu_name, FALSE);
-    $item3 = $this->addMenuLink($item2['mlid'], 'node/' . $node3->id(), $menu_name);
-    $this->assertMenuLink($item1['mlid'], array(
-      'depth' => 1,
-      'has_children' => 1,
-      'p1' => $item1['mlid'],
-      'p2' => 0,
+    $item1 = $this->addMenuLink('', 'node/' . $node1->id(), $menu_name, TRUE);
+    $item2 = $this->addMenuLink($item1->getPluginId(), 'node/' . $node2->id(), $menu_name, FALSE);
+    $item3 = $this->addMenuLink($item2->getPluginId(), 'node/' . $node3->id(), $menu_name);
+
+    // Hierarchy
+    // <$menu_name>
+    // - item1
+    // -- item2
+    // --- item3
+
+    $this->assertMenuLink($item1->getPluginId(), array(
+      'children' => array($item2->getPluginId(), $item3->getPluginId()),
+      'parents' => array($item1->getPluginId()),
       // We assert the language code here to make sure that the language
       // selection element degrades gracefully without the Language module.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item2['mlid'], array(
-      'depth' => 2, 'has_children' => 1,
-      'p1' => $item1['mlid'],
-      'p2' => $item2['mlid'],
-      'p3' => 0,
+    $this->assertMenuLink($item2->getPluginId(), array(
+      'children' => array($item3->getPluginId()),
+      'parents' => array($item2->getPluginId(), $item1->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item3['mlid'], array(
-      'depth' => 3,
-      'has_children' => 0,
-      'p1' => $item1['mlid'],
-      'p2' => $item2['mlid'],
-      'p3' => $item3['mlid'],
-      'p4' => 0,
+    $this->assertMenuLink($item3->getPluginId(), array(
+      'children' => array(),
+      'parents' => array($item3->getPluginId(), $item2->getPluginId(), $item1->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
@@ -282,34 +290,37 @@ function doMenuTests() {
     $this->verifyMenuLink($item3, $node3, $item2, $node2);
 
     // Add more menu links.
-    $item4 = $this->addMenuLink(0, 'node/' . $node4->id(), $menu_name);
-    $item5 = $this->addMenuLink($item4['mlid'], 'node/' . $node5->id(), $menu_name);
+    $item4 = $this->addMenuLink('', 'node/' . $node4->id(), $menu_name);
+    $item5 = $this->addMenuLink($item4->getPluginId(), 'node/' . $node5->id(), $menu_name);
     // Create a menu link pointing to an alias.
-    $item6 = $this->addMenuLink($item4['mlid'], 'node5', $menu_name, TRUE, '0', 'node/' . $node5->id());
-    $this->assertMenuLink($item4['mlid'], array(
-      'depth' => 1,
-      'has_children' => 1,
-      'p1' => $item4['mlid'],
-      'p2' => 0,
+    $item6 = $this->addMenuLink($item4->getPluginId(), 'node5', $menu_name, TRUE, '0');
+
+    // Hierarchy
+    // <$menu_name>
+    // - item1
+    // -- item2
+    // --- item3
+    // - item4
+    // -- item5
+    // -- item6
+
+    $this->assertMenuLink($item4->getPluginId(), array(
+      'children' => array($item5->getPluginId(), $item6->getPluginId()),
+      'parents' => array($item4->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item5['mlid'], array(
-      'depth' => 2,
-      'has_children' => 0,
-      'p1' => $item4['mlid'],
-      'p2' => $item5['mlid'],
-      'p3' => 0,
-      // See above.
+    $this->assertMenuLink($item5->getPluginId(), array(
+      'children' => array(),
+      'parents' => array($item5->getPluginId(), $item4->getPluginId()),
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item6['mlid'], array(
-      'depth' => 2,
-      'has_children' => 0,
-      'p1' => $item4['mlid'],
-      'p2' => $item6['mlid'],
-      'p3' => 0,
-      'link_path' => 'node/' . $node5->id(),
+    $this->assertMenuLink($item6->getPluginId(), array(
+      'children' => array(),
+      'parents' => array($item6->getPluginId(), $item4->getPluginId()),
+      'route_name' => 'node.view',
+      'route_parameters' => array('node' => $node5->id()),
+      'url' => '',
       // See above.
       'langcode' => 'en',
     ));
@@ -323,50 +334,44 @@ function doMenuTests() {
     $this->toggleMenuLink($item2);
 
     // Move link and verify that descendants are updated.
-    $this->moveMenuLink($item2, $item5['mlid'], $menu_name);
-    $this->assertMenuLink($item1['mlid'], array(
-      'depth' => 1,
-      'has_children' => 0,
-      'p1' => $item1['mlid'],
-      'p2' => 0,
+    $this->moveMenuLink($item2, $item5->getPluginId(), $menu_name);
+    // Hierarchy
+    // <$menu_name>
+    // - item1
+    // - item4
+    // -- item5
+    // --- item2
+    // ---- item3
+    // -- item6
+
+    $this->assertMenuLink($item1->getPluginId(), array(
+      'children' => array(),
+      'parents' => array($item1->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item4['mlid'], array(
-      'depth' => 1,
-      'has_children' => 1,
-      'p1' => $item4['mlid'],
-      'p2' => 0,
+    $this->assertMenuLink($item4->getPluginId(), array(
+      'children' => array($item5->getPluginId(), $item6->getPluginId(), $item2->getPluginId(), $item3->getPluginId()),
+      'parents' => array($item4->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item5['mlid'], array(
-      'depth' => 2,
-      'has_children' => 1,
-      'p1' => $item4['mlid'],
-      'p2' => $item5['mlid'],
-      'p3' => 0,
+
+    $this->assertMenuLink($item5->getPluginId(), array(
+      'children' => array($item2->getPluginId(), $item3->getPluginId()),
+      'parents' => array($item5->getPluginId(), $item4->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item2['mlid'], array(
-      'depth' => 3,
-      'has_children' => 1,
-      'p1' => $item4['mlid'],
-      'p2' => $item5['mlid'],
-      'p3' => $item2['mlid'],
-      'p4' => 0,
+    $this->assertMenuLink($item2->getPluginId(), array(
+      'children' => array($item3->getPluginId()),
+      'parents' => array($item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
-    $this->assertMenuLink($item3['mlid'], array(
-      'depth' => 4,
-      'has_children' => 0,
-      'p1' => $item4['mlid'],
-      'p2' => $item5['mlid'],
-      'p3' => $item2['mlid'],
-      'p4' => $item3['mlid'],
-      'p5' => 0,
+    $this->assertMenuLink($item3->getPluginId(), array(
+      'children' => array(),
+      'parents' => array($item3->getPluginId(), $item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()),
       // See above.
       'langcode' => 'en',
     ));
@@ -375,33 +380,39 @@ function doMenuTests() {
     // item's weight doesn't get changed because of the old hardcoded delta=50.
     $items = array();
     for ($i = -50; $i <= 51; $i++) {
-      $items[$i] = $this->addMenuLink(0, 'node/' . $node1->id(), $menu_name, TRUE, strval($i));
+      $items[$i] = $this->addMenuLink('', 'node/' . $node1->id(), $menu_name, TRUE, strval($i));
     }
-    $this->assertMenuLink($items[51]['mlid'], array('weight' => '51'));
+    $this->assertMenuLink($items[51]->getPluginId(), array('weight' => '51'));
 
-    // Enable a link via the overview form.
+    // Disable a link and then re-enable the link via the overview form.
     $this->disableMenuLink($item1);
     $edit = array();
-
-    // Note in the UI the 'links[mlid:x][hidden]' form element maps to enabled,
-    // or NOT hidden.
-    $edit['links[mlid:' . $item1['mlid'] . '][hidden]'] = TRUE;
-    $this->drupalPostForm('admin/structure/menu/manage/' . $item1['menu_name'], $edit, t('Save'));
+    $edit['links[menu_plugin_id:' . $item1->getPluginId() . '][enabled]'] = TRUE;
+    $this->drupalPostForm('admin/structure/menu/manage/' . $item1->getMenuName(), $edit, t('Save'));
+
+    // Mark item2, item4 and item5 as expanded.
+    // This is done in order to show them on the frontpage.
+    $item2->expanded->value = 1;
+    $item2->save();
+    $item4->expanded->value = 1;
+    $item4->save();
+    $item5->expanded->value = 1;
+    $item5->save();
 
     // Verify in the database.
-    $this->assertMenuLink($item1['mlid'], array('hidden' => 0));
+    $this->assertMenuLink($item1->getPluginId(), array('hidden' => 0));
 
     // Add an external link.
-    $item7 = $this->addMenuLink(0, 'http://drupal.org', $menu_name);
-    $this->assertMenuLink($item7['mlid'], array('link_path' => 'http://drupal.org', 'external' => 1));
+    $item7 = $this->addMenuLink('', 'http://drupal.org', $menu_name);
+    $this->assertMenuLink($item7->getPluginId(), array('url' => 'http://drupal.org'));
 
     // Add <front> menu item.
-    $item8 = $this->addMenuLink(0, '<front>', $menu_name);
-    $this->assertMenuLink($item8['mlid'], array('link_path' => '<front>', 'external' => 1));
+    $item8 = $this->addMenuLink('', '<front>', $menu_name);
+    $this->assertMenuLink($item8->getPluginId(), array('route_name' => '<front>'));
     $this->drupalGet('');
     $this->assertResponse(200);
     // Make sure we get routed correctly.
-    $this->clickLink($item8['link_title']);
+    $this->clickLink($item8->getTitle());
     $this->assertResponse(200);
 
     // Save menu links for later tests.
@@ -417,16 +428,16 @@ function testMenuQueryAndFragment() {
 
     // Make a path with query and fragment on.
     $path = 'test-page?arg1=value1&arg2=value2';
-    $item = $this->addMenuLink(0, $path);
+    $item = $this->addMenuLink('', $path);
 
-    $this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
-    $this->assertFieldByName('link_path', $path, 'Path is found with both query and fragment.');
+    $this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
+    $this->assertFieldByName('url', $path, 'Path is found with both query and fragment.');
 
     // Now change the path to something without query and fragment.
     $path = 'test-page';
-    $this->drupalPostForm('admin/structure/menu/item/' . $item['mlid'] . '/edit', array('link_path' => $path), t('Save'));
-    $this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
-    $this->assertFieldByName('link_path', $path, 'Path no longer has query or fragment.');
+    $this->drupalPostForm('admin/structure/menu/item/' . $item->id() . '/edit', array('url' => $path), t('Save'));
+    $this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
+    $this->assertFieldByName('url', $path, 'Path no longer has query or fragment.');
   }
 
   /**
@@ -456,15 +467,15 @@ function testUnpublishedNodeMenuItem() {
       'status' => NODE_NOT_PUBLISHED,
     ));
 
-    $item = $this->addMenuLink(0, 'node/' . $node->id());
+    $item = $this->addMenuLink('', 'node/' . $node->id());
     $this->modifyMenuLink($item);
 
     // Test that a user with 'administer menu' but without 'bypass node access'
     // cannot see the menu item.
     $this->drupalLogout();
     $this->drupalLogin($this->admin_user);
-    $this->drupalGet('admin/structure/menu/manage/' . $item['menu_name']);
-    $this->assertNoText($item['link_title'], "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
+    $this->drupalGet('admin/structure/menu/manage/' . $item->getMenuName());
+    $this->assertNoText($item->getTitle(), "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
   }
 
   /**
@@ -490,42 +501,12 @@ public function testBlockContextualLinks() {
   }
 
   /**
-   * Tests menu link bundles.
-   */
-  public function testMenuBundles() {
-    $this->drupalLogin($this->admin_user);
-    $menu = $this->addCustomMenu();
-    // Clear the entity cache to ensure the static caches are rebuilt.
-    \Drupal::entityManager()->clearCachedBundles();
-    $bundles = entity_get_bundles('menu_link');
-    $this->assertTrue(isset($bundles[$menu->id()]));
-    $menus = menu_list_system_menus();
-    $menus[$menu->id()] = $menu->label();
-    ksort($menus);
-    $this->assertIdentical(array_keys($bundles), array_keys($menus));
-
-    // Test if moving a menu link between menus changes the bundle.
-    $node = $this->drupalCreateNode(array('type' => 'article'));
-    $item = $this->addMenuLink(0, 'node/' . $node->id(), 'tools');
-    $this->moveMenuLink($item, 0, $menu->id());
-    $this->assertEqual($item->bundle(), 'tools', 'Menu link bundle matches the menu');
-
-    $moved_item = entity_load('menu_link', $item->id(), TRUE);
-    $this->assertNotEqual($moved_item->bundle(), $item->bundle(), 'Menu link bundle was changed');
-    $this->assertEqual($moved_item->bundle(), $menu->id(), 'Menu link bundle matches the menu');
-
-    $unsaved_item = entity_create('menu_link', array('menu_name' => $menu->id(), 'link_title' => $this->randomName(16), 'link_path' => '<front>'));
-    $this->assertEqual($unsaved_item->bundle(), $menu->id(), 'Unsaved menu link bundle matches the menu');
-    $this->assertEqual($unsaved_item->menu_name, $menu->id(), 'Unsaved menu link menu name matches the menu');
-  }
-
-  /**
    * Adds a menu link using the UI.
    *
-   * @param integer $plid
+   * @param string $parent
    *   Optional parent menu link id.
-   * @param string $link
-   *   Link path. Defaults to the front page.
+   * @param string $path
+   *   The path to enter on the form. Defaults to the front page.
    * @param string $menu_name
    *   Menu name. Defaults to 'tools'.
    * @param bool $expanded
@@ -534,40 +515,36 @@ public function testMenuBundles() {
    *   to FALSE.
    * @param string $weight
    *  Menu weight. Defaults to 0.
-   * @param string $actual_link
-   *   Actual link path in case $link is an alias.
    *
-   * @return \Drupal\menu_link\Entity\MenuLink
+   * @return \Drupal\menu_link_content\Entity\MenuLinkContent
    *   A menu link entity.
    */
-  function addMenuLink($plid = 0, $link = '<front>', $menu_name = 'tools', $expanded = TRUE, $weight = '0', $actual_link = FALSE) {
+  function addMenuLink($parent = '', $path = '<front>', $menu_name = 'tools', $expanded = FALSE, $weight = '0') {
     // View add menu link page.
     $this->drupalGet("admin/structure/menu/manage/$menu_name/add");
     $this->assertResponse(200);
 
     $title = '!link_' . $this->randomName(16);
     $edit = array(
-      'link_path' => $link,
-      'link_title' => $title,
-      'description' => '',
-      'enabled' => TRUE,
-      'expanded' => $expanded,
-      'parent' =>  $menu_name . ':' . $plid,
-      'weight' => $weight,
+      'url' => $path,
+      'title[0][value]' => $title,
+      'description[0][value]' => '',
+      'enabled' => 1,
+      'expanded[value]' => $expanded,
+      'menu_parent' =>  $menu_name . ':' . $parent,
+      'weight[0][value]' => $weight,
     );
 
-    if (!$actual_link) {
-      $actual_link = $link;
-    }
     // Add menu link.
     $this->drupalPostForm(NULL, $edit, t('Save'));
     $this->assertResponse(200);
     $this->assertText('The menu link has been saved.');
 
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $title));
+    $menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $title));
+
     $menu_link = reset($menu_links);
     $this->assertTrue($menu_link, 'Menu link was found in database.');
-    $this->assertMenuLink($menu_link->id(), array('menu_name' => $menu_name, 'link_path' => $actual_link, 'has_children' => 0, 'plid' => $plid));
+    $this->assertMenuLink($menu_link->getPluginId(), array('menu_name' => $menu_name, 'children' => array(), 'parent' => $parent));
 
     return $menu_link;
   }
@@ -578,27 +555,27 @@ function addMenuLink($plid = 0, $link = '<front>', $menu_name = 'tools', $expand
   function addInvalidMenuLink() {
     foreach (array('-&-', 'admin/people/permissions', '#') as $link_path) {
       $edit = array(
-        'link_path' => $link_path,
-        'link_title' => 'title',
+        'url' => $link_path,
+        'title[0][value]' => 'title',
       );
       $this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
-      $this->assertRaw(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $link_path)), 'Menu link was not created');
+      $this->assertRaw(t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $link_path)), 'Menu link was not created');
     }
   }
 
   /**
    * Verifies a menu link using the UI.
    *
-   * @param array $item
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
    *   Menu link.
    * @param object $item_node
    *   Menu link content node.
-   * @param array $parent
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $parent
    *   Parent menu link.
    * @param object $parent_node
    *   Parent menu link content node.
    */
-  function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL) {
+  function verifyMenuLink(MenuLinkContent $item, $item_node, MenuLinkContent $parent = NULL, $parent_node = NULL) {
     // View home page.
     $this->drupalGet('');
     $this->assertResponse(200);
@@ -606,7 +583,7 @@ function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL)
     // Verify parent menu link.
     if (isset($parent)) {
       // Verify menu link.
-      $title = $parent['link_title'];
+      $title = $parent->getTitle();
       $this->assertLink($title, 0, 'Parent menu link was displayed');
 
       // Verify menu link link.
@@ -616,7 +593,7 @@ function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL)
     }
 
     // Verify menu link.
-    $title = $item['link_title'];
+    $title = $item->getTitle();
     $this->assertLink($title, 0, 'Menu link was displayed');
 
     // Verify menu link link.
@@ -628,18 +605,18 @@ function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL)
   /**
    * Changes the parent of a menu link using the UI.
    *
-   * @param array $item
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContentInterface $item
    *   The menu link item to move.
-   * @param int $plid
+   * @param int $parent
    *   The id of the new parent.
    * @param string $menu_name
    *   The menu the menu link will be moved to.
    */
-  function moveMenuLink($item, $plid, $menu_name) {
-    $mlid = $item['mlid'];
+  function moveMenuLink(MenuLinkContent $item, $parent, $menu_name) {
+    $mlid = $item->id();
 
     $edit = array(
-      'parent' => $menu_name . ':' . $plid,
+      'menu_parent' => $menu_name . ':' . $parent,
     );
     $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
     $this->assertResponse(200);
@@ -648,58 +625,54 @@ function moveMenuLink($item, $plid, $menu_name) {
   /**
    * Modifies a menu link using the UI.
    *
-   * @param array $item
-   *   Menu link passed by reference.
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
+   *   Menu link entity.
    */
-  function modifyMenuLink(&$item) {
-    $item['link_title'] = $this->randomName(16);
+  function modifyMenuLink(MenuLinkContent $item) {
+    $item->title->value = $this->randomName(16);
 
-    $mlid = $item['mlid'];
-    $title = $item['link_title'];
+    $mlid = $item->id();
+    $title = $item->getTitle();
 
     // Edit menu link.
     $edit = array();
-    $edit['link_title'] = $title;
+    $edit['title[0][value]'] = $title;
     $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
     $this->assertResponse(200);
     $this->assertText('The menu link has been saved.');
     // Verify menu link.
-    $this->drupalGet('admin/structure/menu/manage/' . $item['menu_name']);
+    $this->drupalGet('admin/structure/menu/manage/' . $item->getMenuName());
     $this->assertText($title, 'Menu link was edited');
   }
 
   /**
    * Resets a standard menu link using the UI.
    *
-   * @param array $item
-   *   Menu link.
-   * @param string $old_title
+   * @param \Drupal\Core\Menu\MenuLinkInterface $menu_link
+   *   The Menu link.
+   * @param int $old_weight
    *   Original title for menu link.
    */
-  function resetMenuLink($item, $old_title) {
-    $mlid = $item['mlid'];
-    $title = $item['link_title'];
-
+  function resetMenuLink(MenuLinkInterface $menu_link, $old_weight) {
     // Reset menu link.
-    $this->drupalPostForm("admin/structure/menu/item/$mlid/reset", array(), t('Reset'));
+    $this->drupalPostForm("admin/structure/menu/link/{$menu_link->getPluginId()}/reset", array(), t('Reset'));
     $this->assertResponse(200);
     $this->assertRaw(t('The menu link was reset to its default settings.'), 'Menu link was reset');
 
     // Verify menu link.
-    $this->drupalGet('');
-    $this->assertNoText($title, 'Menu link was reset');
-    $this->assertText($old_title, 'Menu link was reset');
+    $instance = \Drupal::service('plugin.manager.menu.link')->createInstance($menu_link->getPluginId());
+    $this->assertEqual($old_weight, $instance->getWeight(), 'Resets to the old weight.');
   }
 
   /**
    * Deletes a menu link using the UI.
    *
-   * @param array $item
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
    *   Menu link.
    */
-  function deleteMenuLink($item) {
-    $mlid = $item['mlid'];
-    $title = $item['link_title'];
+  function deleteMenuLink(MenuLinkContent $item) {
+    $mlid = $item->id();
+    $title = $item->getTitle();
 
     // Delete menu link.
     $this->drupalPostForm("admin/structure/menu/item/$mlid/delete", array(), t('Confirm'));
@@ -714,51 +687,51 @@ function deleteMenuLink($item) {
   /**
    * Alternately disables and enables a menu link.
    *
-   * @param $item
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
    *   Menu link.
    */
-  function toggleMenuLink($item) {
+  function toggleMenuLink(MenuLinkContent $item) {
     $this->disableMenuLink($item);
 
     // Verify menu link is absent.
     $this->drupalGet('');
-    $this->assertNoText($item['link_title'], 'Menu link was not displayed');
+    $this->assertNoText($item->getTitle(), 'Menu link was not displayed');
     $this->enableMenuLink($item);
 
     // Verify menu link is displayed.
     $this->drupalGet('');
-    $this->assertText($item['link_title'], 'Menu link was displayed');
+    $this->assertText($item->getTitle(), 'Menu link was displayed');
   }
 
   /**
    * Disables a menu link.
    *
-   * @param $item
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
    *   Menu link.
    */
-  function disableMenuLink($item) {
-    $mlid = $item['mlid'];
+  function disableMenuLink(MenuLinkContent $item) {
+    $mlid = $item->id();
     $edit['enabled'] = FALSE;
     $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
 
     // Unlike most other modules, there is no confirmation message displayed.
     // Verify in the database.
-    $this->assertMenuLink($mlid, array('hidden' => 1));
+    $this->assertMenuLink($item->getPluginId(), array('hidden' => 1));
   }
 
   /**
    * Enables a menu link.
    *
-   * @param $item
+   * @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
    *   Menu link.
    */
-  function enableMenuLink($item) {
-    $mlid = $item['mlid'];
+  function enableMenuLink(MenuLinkContent $item) {
+    $mlid = $item->id();
     $edit['enabled'] = TRUE;
     $this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
 
     // Verify in the database.
-    $this->assertMenuLink($mlid, array('hidden' => 0));
+    $this->assertMenuLink($item->getPluginId(), array('hidden' => 0));
   }
 
   /**
@@ -782,27 +755,19 @@ public function testMenuParentsJsAccess() {
   /**
    * Returns standard menu link.
    *
-   * @return \Drupal\menu_link\Entity\MenuLink
-   *   A menu link entity.
+   * @return \Drupal\Core\Menu\MenuLinkInterface
+   *   A menu link plugin.
    */
   private function getStandardMenuLink() {
-    $mlid = 0;
     // Retrieve menu link id of the Log out menu link, which will always be on
     // the front page.
-    $query = \Drupal::entityQuery('menu_link')
-      ->condition('module', 'user')
-      ->condition('machine_name', 'user.logout');
-    $result = $query->execute();
-    if (!empty($result)) {
-      $mlid = reset($result);
-    }
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $result = $menu_link_manager->loadLinksByRoute('user.logout');
+    $instance = reset($result);
 
-    $this->assertTrue($mlid > 0, 'Standard menu link id was found');
-    // Load menu link.
-    // Use api function so that link is translated for rendering.
-    $item = entity_load('menu_link', $mlid);
-    $this->assertTrue((bool) $item, 'Standard menu link was loaded');
-    return $item;
+    $this->assertTrue((bool) $instance, 'Standard menu link was loaded');
+    return $instance;
   }
 
   /**
@@ -833,9 +798,9 @@ private function verifyAccess($response = 200) {
       $this->assertText(t('Tools'), 'Tools menu page was displayed');
     }
 
-    // View menu edit page.
+    // View menu edit page for a static link.
     $item = $this->getStandardMenuLink();
-    $this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
+    $this->drupalGet('admin/structure/menu/link/' . $item->getPluginId() . '/edit');
     $this->assertResponse($response);
     if ($response == 200) {
       $this->assertText(t('Edit menu item'), 'Menu edit page was displayed');
diff --git a/core/modules/menu_ui/src/Tests/MenuWebTestBase.php b/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
index 5f16536..6069197 100644
--- a/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
+++ b/core/modules/menu_ui/src/Tests/MenuWebTestBase.php
@@ -19,28 +19,58 @@
    *
    * @var array
    */
-  public static $modules = array('menu_ui');
+  public static $modules = array('menu_ui', 'menu_link_content');
 
   /**
    * Fetchs the menu item from the database and compares it to expected item.
    *
-   * @param int $mlid
+   * @param int $menu_plugin_id
    *   Menu item id.
-   * @param array $item
+   * @param array $expected_item
    *   Array containing properties to verify.
    */
-  function assertMenuLink($mlid, array $expected_item) {
+  function assertMenuLink($menu_plugin_id, array $expected_item) {
     // Retrieve menu link.
-    $item = entity_load('menu_link', $mlid);
-    $options = $item->options;
-    if (!empty($options['query'])) {
-      $item['link_path'] .= '?' . \Drupal::urlGenerator()->httpBuildQuery($options['query']);
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $menu_link_manager->resetDefinitions();
+    // Reset the static load cache.
+    \Drupal::entityManager()->getStorage('menu_link_content')->resetCache();
+    $definition = $menu_link_manager->getDefinition($menu_plugin_id);
+
+    $entity = NULL;
+
+    // Pull the path from the menu link content.
+    if (strpos($menu_plugin_id, 'menu_link_content') === 0) {
+      list(, $uuid) = explode(':', $menu_plugin_id, 2);
+      /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
+      $entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $uuid);
+    }
+
+    if (isset($expected_item['children'])) {
+      $child_ids = array_values($menu_link_manager->getChildIds($menu_plugin_id));
+      sort($expected_item['children']);
+      if ($child_ids) {
+        sort($child_ids);
+      }
+      $this->assertEqual($expected_item['children'], $child_ids);
+      unset($expected_item['children']);
     }
-    if (!empty($options['fragment'])) {
-      $item['link_path'] .= '#' . $options['fragment'];
+
+    if (isset($expected_item['parents'])) {
+      $parent_ids = array_values($menu_link_manager->getParentIds($menu_plugin_id));
+      $this->assertEqual($expected_item['parents'], $parent_ids);
+      unset($expected_item['parents']);
+    }
+
+    if (isset($expected_item['langcode']) && $entity) {
+      $this->assertEqual($entity->langcode->value, $expected_item['langcode']);
+      unset($expected_item['langcode']);
     }
+
     foreach ($expected_item as $key => $value) {
-      $this->assertEqual($item[$key], $value);
+      $this->assertTrue(isset($definition[$key]));
+      $this->assertEqual($definition[$key], $value);
     }
   }
 
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateFilterFormatTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateFilterFormatTest.php
index c1529b8..807e4f5 100644
--- a/core/modules/migrate_drupal/src/Tests/d6/MigrateFilterFormatTest.php
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateFilterFormatTest.php
@@ -50,9 +50,9 @@ public function testFilterFormat() {
     $this->assertTrue($filters['filter_html']['status']);
 
     // These should be false by default.
-    $this->assertFalse($filters['filter_html_escape']['status']);
-    $this->assertFalse($filters['filter_caption']['status']);
-    $this->assertFalse($filters['filter_html_image_secure']['status']);
+    $this->assertFalse(isset($filters['filter_html_escape']));
+    $this->assertFalse(isset($filters['filter_caption']));
+    $this->assertFalse(isset($filters['filter_html_image_secure']));
 
     // Check variables migrated into filter.
     $this->assertIdentical($filters['filter_html']['settings']['allowed_html'], '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>');
diff --git a/core/modules/node/config/install/views.view.archive.yml b/core/modules/node/config/install/views.view.archive.yml
index 7b86429..e83b8e1 100644
--- a/core/modules/node/config/install/views.view.archive.yml
+++ b/core/modules/node/config/install/views.view.archive.yml
@@ -140,6 +140,7 @@ display:
     display_title: Block
     display_plugin: block
     position: 1
+    provider: block
     display_options:
       query:
         type: views_query
@@ -173,3 +174,5 @@ langcode: en
 dependencies:
   module:
     - node
+    - block
+
diff --git a/core/modules/node/config/install/views.view.content_recent.yml b/core/modules/node/config/install/views.view.content_recent.yml
index 8e231b2..726628d 100644
--- a/core/modules/node/config/install/views.view.content_recent.yml
+++ b/core/modules/node/config/install/views.view.content_recent.yml
@@ -460,6 +460,7 @@ display:
     display_options:
       link_url: admin/content
       block_category: 'Lists (Views)'
+    provider: block
 label: 'Recent content'
 module: node
 id: content_recent
@@ -469,3 +470,5 @@ dependencies:
   module:
     - node
     - user
+    - block
+
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index dd47b47..9ac1c40 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -420,11 +420,11 @@ function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) {
  * @param $form
  *   The form being used to edit the node.
  * @param $form_state
- *   The form state array.
+ *   The current state of the form.
  *
  * @ingroup entity_crud
  */
-function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_state) {
+function hook_node_validate(\Drupal\node\NodeInterface $node, $form, \Drupal\Core\Form\FormStateInterface $form_state) {
   if (isset($node->end) && isset($node->start)) {
     if ($node->start > $node->end) {
       form_set_error('time', $form_state, t('An event may not end before it starts.'));
@@ -447,15 +447,15 @@ function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_stat
  * @param $form
  *   The form being used to edit the node.
  * @param $form_state
- *   The form state array.
+ *   The current state of the form.
  *
  * @ingroup entity_crud
  */
-function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state) {
-  // Decompose the selected menu parent option into 'menu_name' and 'plid', if
+function hook_node_submit(\Drupal\node\NodeInterface $node, $form, \Drupal\Core\Form\FormStateInterface $form_state) {
+  // Decompose the selected menu parent option into 'menu_name' and 'parent', if
   // the form used the default parent selection widget.
   if (!empty($form_state['values']['menu']['parent'])) {
-    list($node->menu['menu_name'], $node->menu['plid']) = explode(':', $form_state['values']['menu']['parent']);
+    list($node->menu['menu_name'], $node->menu['parent']) = explode(':', $form_state['values']['menu']['parent']);
   }
 }
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 1a27d14..fdec8ba 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -9,6 +9,7 @@
  */
 
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -1053,7 +1054,7 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $langcode = NULL) {
  * @see taxonomy_term_page()
  * @see node_form_system_site_information_settings_form_submit()
  */
-function node_form_system_site_information_settings_form_alter(&$form, &$form_state, $form_id) {
+function node_form_system_site_information_settings_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $options = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30);
   $form['front_page']['default_nodes_main'] = array(
     '#type' => 'select',
@@ -1071,7 +1072,7 @@ function node_form_system_site_information_settings_form_alter(&$form, &$form_st
  *
  * @see node_form_system_site_information_settings_form_alter()
  */
-function node_form_system_site_information_settings_form_submit($form, &$form_state) {
+function node_form_system_site_information_settings_form_submit($form, FormStateInterface $form_state) {
   \Drupal::config('node.settings')
     ->set('items_per_page', $form_state['values']['default_nodes_main'])
     ->save();
@@ -1084,7 +1085,7 @@ function node_form_system_site_information_settings_form_submit($form, &$form_st
  *
  * @see node_form_system_themes_admin_form_submit()
  */
-function node_form_system_themes_admin_form_alter(&$form, &$form_state, $form_id) {
+function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $form['admin_theme']['use_admin_theme'] = array(
     '#type' => 'checkbox',
     '#title' => t('Use the administration theme when editing or creating content'),
@@ -1098,7 +1099,7 @@ function node_form_system_themes_admin_form_alter(&$form, &$form_state, $form_id
  *
  * @see node_form_system_themes_admin_form_alter()
  */
-function node_form_system_themes_admin_form_submit($form, &$form_state) {
+function node_form_system_themes_admin_form_submit($form, FormStateInterface $form_state) {
   \Drupal::config('node.settings')
     ->set('use_admin_theme', $form_state['values']['use_admin_theme'])
     ->save();
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 9757596..e848f3e 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -10,6 +10,7 @@
  */
 
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Drupal\node\NodeInterface;
 
@@ -48,7 +49,7 @@ function template_preprocess_node_add_list(&$variables) {
  *
  * @see node_form_build_preview()
  */
-function node_preview(NodeInterface $node, array &$form_state) {
+function node_preview(NodeInterface $node, FormStateInterface $form_state) {
   if ($node->access('create') || $node->access('update')) {
 
     $node->changed = REQUEST_TIME;
diff --git a/core/modules/node/src/Form/DeleteMultiple.php b/core/modules/node/src/Form/DeleteMultiple.php
index 4044098..a067ccb 100644
--- a/core/modules/node/src/Form/DeleteMultiple.php
+++ b/core/modules/node/src/Form/DeleteMultiple.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Url;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\TempStoreFactory;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -95,7 +96,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $this->nodes = $this->tempStoreFactory->get('node_multiple_delete_confirm')->get(\Drupal::currentUser()->id());
     if (empty($this->nodes)) {
       return new RedirectResponse(url('admin/content', array('absolute' => TRUE)));
@@ -115,7 +116,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['confirm'] && !empty($this->nodes)) {
       $this->storage->delete($this->nodes);
       $this->tempStoreFactory->get('node_multiple_delete_confirm')->delete(\Drupal::currentUser()->id());
diff --git a/core/modules/node/src/Form/NodeDeleteForm.php b/core/modules/node/src/Form/NodeDeleteForm.php
index 3b5a615..19faa67 100644
--- a/core/modules/node/src/Form/NodeDeleteForm.php
+++ b/core/modules/node/src/Form/NodeDeleteForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -71,7 +72,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     watchdog('content', '@type: deleted %title.', array('@type' => $this->entity->bundle(), '%title' => $this->entity->label()));
     $node_type_storage = $this->entityManager->getStorage('node_type');
diff --git a/core/modules/node/src/Form/NodeRevisionDeleteForm.php b/core/modules/node/src/Form/NodeRevisionDeleteForm.php
index 3f240e4..0ab753d 100644
--- a/core/modules/node/src/Form/NodeRevisionDeleteForm.php
+++ b/core/modules/node/src/Form/NodeRevisionDeleteForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -106,7 +107,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $node_revision = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $node_revision = NULL) {
     $this->revision = $this->nodeStorage->loadRevision($node_revision);
     $form = parent::buildForm($form, $form_state);
 
@@ -116,7 +117,7 @@ public function buildForm(array $form, array &$form_state, $node_revision = NULL
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->nodeStorage->deleteRevision($this->revision->getRevisionId());
 
     watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $this->revision->bundle(), '%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()));
diff --git a/core/modules/node/src/Form/NodeRevisionRevertForm.php b/core/modules/node/src/Form/NodeRevisionRevertForm.php
index a1e7c45..147036f 100644
--- a/core/modules/node/src/Form/NodeRevisionRevertForm.php
+++ b/core/modules/node/src/Form/NodeRevisionRevertForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -89,7 +90,7 @@ public function getDescription() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $node_revision = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $node_revision = NULL) {
     $this->revision = $this->nodeStorage->loadRevision($node_revision);
     $form = parent::buildForm($form, $form_state);
 
@@ -99,7 +100,7 @@ public function buildForm(array $form, array &$form_state, $node_revision = NULL
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->revision->setNewRevision();
     // Make this the new default revision for the node.
     $this->revision->isDefaultRevision(TRUE);
diff --git a/core/modules/node/src/Form/NodeTypeDeleteConfirm.php b/core/modules/node/src/Form/NodeTypeDeleteConfirm.php
index fdd71e8..0c23ced 100644
--- a/core/modules/node/src/Form/NodeTypeDeleteConfirm.php
+++ b/core/modules/node/src/Form/NodeTypeDeleteConfirm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Database\Connection;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -67,7 +68,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $num_nodes = $this->database->query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $this->entity->id()))->fetchField();
     if ($num_nodes) {
       $caption = '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', array('%type' => $this->entity->label())) . '</p>';
@@ -82,7 +83,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     $t_args = array('%name' => $this->entity->label());
     drupal_set_message(t('The content type %name has been deleted.', $t_args));
diff --git a/core/modules/node/src/Form/RebuildPermissionsForm.php b/core/modules/node/src/Form/RebuildPermissionsForm.php
index 490c3d2..9f8da72 100644
--- a/core/modules/node/src/Form/RebuildPermissionsForm.php
+++ b/core/modules/node/src/Form/RebuildPermissionsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\node\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 class RebuildPermissionsForm extends ConfirmFormBase {
@@ -50,7 +51,7 @@ public function getDescription() {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     node_access_rebuild(TRUE);
     $form_state['redirect_route'] = $this->getCancelUrl();
   }
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php
index 69d91a5..bf4b869 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/NodeForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Component\Utility\String;
 
@@ -43,9 +44,9 @@ protected function prepareEntity() {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::form().
+   * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\node\NodeInterface $node */
     $node = $this->entity;
 
@@ -209,9 +210,9 @@ public function form(array $form, array &$form_state) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::actions().
+   * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $element = parent::actions($form, $form_state);
     $node = $this->entity;
     $preview_mode = $this->settings['preview'];
@@ -290,9 +291,9 @@ protected function actions(array $form, array &$form_state) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::validate().
+   * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     $node = $this->buildEntity($form, $form_state);
 
     if ($node->id() && (node_last_changed($node->id(), $this->getFormLangcode($form_state)) > $node->getChangedTime())) {
@@ -331,10 +332,8 @@ public function validate(array $form, array &$form_state) {
    * This function can be called by a "Next" button of a wizard to update the
    * form state's entity with the current step's values before proceeding to the
    * next step.
-   *
-   * Overrides Drupal\Core\Entity\EntityForm::submit().
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // Build the node object from the submitted values.
     $node = parent::submit($form, $form_state);
 
@@ -364,9 +363,9 @@ public function submit(array $form, array &$form_state) {
    * @param $form
    *   An associative array containing the structure of the form.
    * @param $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   *   The current state of the form.
    */
-  public function preview(array $form, array &$form_state) {
+  public function preview(array $form, FormStateInterface $form_state) {
     // @todo Remove this: we should not have explicit includes in autoloaded
     //   classes.
     module_load_include('inc', 'node', 'node.pages');
@@ -380,9 +379,9 @@ public function preview(array $form, array &$form_state) {
    * @param $form
    *   An associative array containing the structure of the form.
    * @param $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   *   The current state of the form.
    */
-  public function publish(array $form, array &$form_state) {
+  public function publish(array $form, FormStateInterface $form_state) {
     $node = $this->entity;
     $node->setPublished(TRUE);
     return $node;
@@ -394,9 +393,9 @@ public function publish(array $form, array &$form_state) {
    * @param $form
    *   An associative array containing the structure of the form.
    * @param $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   *   The current state of the form.
    */
-  public function unpublish(array $form, array &$form_state) {
+  public function unpublish(array $form, FormStateInterface $form_state) {
     $node = $this->entity;
     $node->setPublished(FALSE);
     return $node;
@@ -405,7 +404,7 @@ public function unpublish(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\node\NodeInterface $entity */
     $entity = parent::buildEntity($form, $form_state);
     // A user might assign the node author by entering a user name in the node
@@ -426,11 +425,10 @@ public function buildEntity(array $form, array &$form_state) {
     return $entity;
   }
 
-
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::save().
+   * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $node = $this->entity;
     $insert = $node->isNew();
     $node->save();
diff --git a/core/modules/node/src/NodeTranslationHandler.php b/core/modules/node/src/NodeTranslationHandler.php
index 21ab7e0..02afb6c 100644
--- a/core/modules/node/src/NodeTranslationHandler.php
+++ b/core/modules/node/src/NodeTranslationHandler.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines the translation handler for nodes.
@@ -18,7 +19,7 @@ class NodeTranslationHandler extends ContentTranslationHandler {
   /**
    * {@inheritdoc}
    */
-  public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity) {
+  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
     parent::entityFormAlter($form, $form_state, $entity);
 
     // Move the translation fieldset to a vertical tab.
@@ -73,7 +74,7 @@ protected function entityFormTitle(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function entityFormEntityBuild($entity_type, EntityInterface $entity, array $form, array &$form_state) {
+  public function entityFormEntityBuild($entity_type, EntityInterface $entity, array $form, FormStateInterface $form_state) {
     if (isset($form_state['values']['content_translation'])) {
       $form_controller = content_translation_form_controller($form_state);
       $translation = &$form_state['values']['content_translation'];
diff --git a/core/modules/node/src/NodeTypeForm.php b/core/modules/node/src/NodeTypeForm.php
index ec00d50..f8cf927 100644
--- a/core/modules/node/src/NodeTypeForm.php
+++ b/core/modules/node/src/NodeTypeForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for node type forms.
@@ -19,7 +20,7 @@ class NodeTypeForm extends EntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $type = $this->entity;
@@ -152,7 +153,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = t('Save content type');
     $actions['delete']['#value'] = t('Delete content type');
@@ -162,7 +163,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     $id = trim($form_state['values']['type']);
@@ -175,7 +176,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $type = $this->entity;
     $type->type = trim($type->id());
     $type->name = trim($type->name);
diff --git a/core/modules/node/src/Plugin/Action/AssignOwnerNode.php b/core/modules/node/src/Plugin/Action/AssignOwnerNode.php
index 7823ccb..b2ead47 100644
--- a/core/modules/node/src/Plugin/Action/AssignOwnerNode.php
+++ b/core/modules/node/src/Plugin/Action/AssignOwnerNode.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Action\ConfigurableActionBase;
 use Drupal\Core\Database\Connection;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -77,7 +78,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $description = t('The username of the user to which you would like to assign ownership.');
     $count = $this->connection->query("SELECT COUNT(*) FROM {users}")->fetchField();
     $owner_name = '';
@@ -117,7 +118,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
     $exists = (bool) $this->connection->queryRange('SELECT 1 FROM {users} WHERE name = :name', 0, 1, array(':name' => $form_state['values']['owner_name']))->fetchField();
     if (!$exists) {
       form_set_error('owner_name', $form_state, t('Enter a valid username.'));
@@ -127,7 +128,7 @@ public function validateConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['owner_uid'] = $this->connection->query('SELECT uid from {users} WHERE name = :name', array(':name' => $form_state['values']['owner_name']))->fetchField();
   }
 
diff --git a/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php b/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php
index 6fb4674..7dab8be 100644
--- a/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php
+++ b/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Action\ConfigurableActionBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Unpublishes a node containing certain keywords.
@@ -47,7 +48,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['keywords'] = array(
       '#title' => t('Keywords'),
       '#type' => 'textarea',
@@ -60,7 +61,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['keywords'] = Tags::explode($form_state['values']['keywords']);
   }
 
diff --git a/core/modules/node/src/Plugin/Block/SyndicateBlock.php b/core/modules/node/src/Plugin/Block/SyndicateBlock.php
index ace314a..d0038fc 100644
--- a/core/modules/node/src/Plugin/Block/SyndicateBlock.php
+++ b/core/modules/node/src/Plugin/Block/SyndicateBlock.php
@@ -8,6 +8,7 @@
 namespace Drupal\node\Plugin\Block;
 
 use Drupal\block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -50,7 +51,7 @@ public function build() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
     // @see ::isCacheable()
diff --git a/core/modules/node/src/Plugin/Condition/NodeType.php b/core/modules/node/src/Plugin/Condition/NodeType.php
index 612d82d..9727bed 100644
--- a/core/modules/node/src/Plugin/Condition/NodeType.php
+++ b/core/modules/node/src/Plugin/Condition/NodeType.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Condition\ConditionPluginBase;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -68,7 +69,7 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $options = array();
     $node_types = $this->entityStorage->loadMultiple();
     foreach ($node_types as $type) {
@@ -86,7 +87,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['bundles'] = array_filter($form_state['values']['bundles']);
     parent::submitConfigurationForm($form, $form_state);
   }
diff --git a/core/modules/node/src/Plugin/Search/NodeSearch.php b/core/modules/node/src/Plugin/Search/NodeSearch.php
index f8e76a8..45e34b8 100644
--- a/core/modules/node/src/Plugin/Search/NodeSearch.php
+++ b/core/modules/node/src/Plugin/Search/NodeSearch.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Database\Query\SelectExtender;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -398,7 +399,7 @@ public function indexStatus() {
   /**
    * {@inheritdoc}
    */
-  public function searchFormAlter(array &$form, array &$form_state) {
+  public function searchFormAlter(array &$form, FormStateInterface $form_state) {
     // Add advanced search keyword-related boxes.
     $form['advanced'] = array(
       '#type' => 'details',
@@ -560,7 +561,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     // Output form for defining rank factor weights.
     $form['content_ranking'] = array(
       '#type' => 'details',
@@ -589,7 +590,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     foreach ($this->getRankings() as $var => $values) {
       if (!empty($form_state['values']["rankings_$var"])) {
         $this->configuration['rankings'][$var] = $form_state['values']["rankings_$var"];
diff --git a/core/modules/node/src/Plugin/views/field/Language.php b/core/modules/node/src/Plugin/views/field/Language.php
index af705cb..9f7ff51 100644
--- a/core/modules/node/src/Plugin/views/field/Language.php
+++ b/core/modules/node/src/Plugin/views/field/Language.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\node\Plugin\views\field\Node;
 use Drupal\views\ResultRow;
 
@@ -26,7 +27,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['native_language'] = array(
       '#title' => t('Native language'),
diff --git a/core/modules/node/src/Plugin/views/field/Link.php b/core/modules/node/src/Plugin/views/field/Link.php
index d2a89a4..b276747 100644
--- a/core/modules/node/src/Plugin/views/field/Link.php
+++ b/core/modules/node/src/Plugin/views/field/Link.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 
@@ -32,7 +33,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Text to display'),
diff --git a/core/modules/node/src/Plugin/views/field/Node.php b/core/modules/node/src/Plugin/views/field/Node.php
index b85cd02..ae74239 100644
--- a/core/modules/node/src/Plugin/views/field/Node.php
+++ b/core/modules/node/src/Plugin/views/field/Node.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -44,7 +45,7 @@ protected function defineOptions() {
   /**
    * Provide link to node option
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_node'] = array(
       '#title' => t('Link this field to the original piece of content'),
       '#description' => t("Enable to override this field's links."),
diff --git a/core/modules/node/src/Plugin/views/field/Path.php b/core/modules/node/src/Plugin/views/field/Path.php
index a08b7cd..53b5010 100644
--- a/core/modules/node/src/Plugin/views/field/Path.php
+++ b/core/modules/node/src/Plugin/views/field/Path.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -37,7 +38,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['absolute'] = array(
       '#type' => 'checkbox',
diff --git a/core/modules/node/src/Plugin/views/field/Revision.php b/core/modules/node/src/Plugin/views/field/Revision.php
index db18760..040c63f 100644
--- a/core/modules/node/src/Plugin/views/field/Revision.php
+++ b/core/modules/node/src/Plugin/views/field/Revision.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -41,7 +42,7 @@ protected function defineOptions() {
   /**
    * Provide link to revision option.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_node_revision'] = array(
       '#title' => t('Link this field to its content revision'),
       '#description' => t('This will override any other link you have set.'),
diff --git a/core/modules/node/src/Plugin/views/field/Type.php b/core/modules/node/src/Plugin/views/field/Type.php
index 9e1be57..4824227 100644
--- a/core/modules/node/src/Plugin/views/field/Type.php
+++ b/core/modules/node/src/Plugin/views/field/Type.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\node\Plugin\views\field\Node;
 use Drupal\views\ResultRow;
 
@@ -29,7 +30,7 @@ protected function defineOptions() {
   /**
    * Provide machine_name option for to node type display.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['machine_name'] = array(
diff --git a/core/modules/node/src/Plugin/views/filter/Access.php b/core/modules/node/src/Plugin/views/filter/Access.php
index 524426f..8845ca8 100644
--- a/core/modules/node/src/Plugin/views/filter/Access.php
+++ b/core/modules/node/src/Plugin/views/filter/Access.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 
 /**
@@ -19,7 +20,7 @@
 class Access extends FilterPluginBase {
 
   public function adminSummary() { }
-  protected function operatorForm(&$form, &$form_state) { }
+  protected function operatorForm(&$form, FormStateInterface $form_state) { }
   public function canExpose() {
     return FALSE;
   }
diff --git a/core/modules/node/src/Plugin/views/filter/Status.php b/core/modules/node/src/Plugin/views/filter/Status.php
index 08e63d9..35c818e 100644
--- a/core/modules/node/src/Plugin/views/filter/Status.php
+++ b/core/modules/node/src/Plugin/views/filter/Status.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 
 /**
@@ -20,7 +21,7 @@ class Status extends FilterPluginBase {
 
   public function adminSummary() { }
 
-  protected function operatorForm(&$form, &$form_state) { }
+  protected function operatorForm(&$form, FormStateInterface $form_state) { }
 
   public function canExpose() { return FALSE; }
 
diff --git a/core/modules/node/src/Plugin/views/row/NodeRow.php b/core/modules/node/src/Plugin/views/row/NodeRow.php
index de71343..c79691f 100644
--- a/core/modules/node/src/Plugin/views/row/NodeRow.php
+++ b/core/modules/node/src/Plugin/views/row/NodeRow.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\EntityRow;
 
 /**
@@ -38,7 +39,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['links'] = array(
diff --git a/core/modules/node/src/Plugin/views/row/Rss.php b/core/modules/node/src/Plugin/views/row/Rss.php
index 4a7b01d..9d3db7b 100644
--- a/core/modules/node/src/Plugin/views/row/Rss.php
+++ b/core/modules/node/src/Plugin/views/row/Rss.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\RowPluginBase;
 
 /**
@@ -44,7 +45,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['view_mode'] = array(
diff --git a/core/modules/node/src/Plugin/views/wizard/Node.php b/core/modules/node/src/Plugin/views/wizard/Node.php
index fc5aadb..377a6c6 100644
--- a/core/modules/node/src/Plugin/views/wizard/Node.php
+++ b/core/modules/node/src/Plugin/views/wizard/Node.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Plugin\views\wizard;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\wizard\WizardPluginBase;
 
 /**
@@ -86,12 +87,12 @@ protected function rowStyleOptions() {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    * @param string $type
    *   The display ID (e.g. 'page' or 'block').
    */
-  protected function buildFormStyle(array &$form, array &$form_state, $type) {
+  protected function buildFormStyle(array &$form, FormStateInterface $form_state, $type) {
     parent::buildFormStyle($form, $form_state, $type);
     $style_form =& $form['displays'][$type]['options']['style'];
     // Some style plugins don't support row plugins so stop here if that's the
@@ -156,7 +157,7 @@ protected function defaultDisplayOptions() {
   /**
    * Overrides Drupal\views\Plugin\views\wizard\WizardPluginBase::defaultDisplayFiltersUser().
    */
-  protected function defaultDisplayFiltersUser(array $form, array &$form_state) {
+  protected function defaultDisplayFiltersUser(array $form, FormStateInterface $form_state) {
     $filters = parent::defaultDisplayFiltersUser($form, $form_state);
 
     if (!empty($form_state['values']['show']['tagged_with']['tids'])) {
@@ -183,7 +184,7 @@ protected function defaultDisplayFiltersUser(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function pageDisplayOptions(array $form, array &$form_state) {
+  protected function pageDisplayOptions(array $form, FormStateInterface $form_state) {
     $display_options = parent::pageDisplayOptions($form, $form_state);
     $row_plugin = isset($form_state['values']['page']['style']['row_plugin']) ? $form_state['values']['page']['style']['row_plugin'] : NULL;
     $row_options = isset($form_state['values']['page']['style']['row_options']) ? $form_state['values']['page']['style']['row_options'] : array();
@@ -194,7 +195,7 @@ protected function pageDisplayOptions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function blockDisplayOptions(array $form, array &$form_state) {
+  protected function blockDisplayOptions(array $form, FormStateInterface $form_state) {
     $display_options = parent::blockDisplayOptions($form, $form_state);
     $row_plugin = isset($form_state['values']['block']['style']['row_plugin']) ? $form_state['values']['block']['style']['row_plugin'] : NULL;
     $row_options = isset($form_state['values']['block']['style']['row_options']) ? $form_state['values']['block']['style']['row_options'] : array();
@@ -233,7 +234,7 @@ protected  function display_options_row(&$display_options, $row_plugin, $row_opt
    *
    * Add some options for filter by taxonomy terms.
    */
-  protected function buildFilters(&$form, &$form_state) {
+  protected function buildFilters(&$form, FormStateInterface $form_state) {
     parent::buildFilters($form, $form_state);
 
     $selected_bundle = static::getSelected($form_state, array('show', 'type'), 'all', $form['displays']['show']['type']);
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
index ede945e..43ef3cb 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\options\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\OptGroup;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\AllowedValuesInterface;
@@ -72,7 +73,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $allowed_values = $this->getSetting('allowed_values');
     $allowed_values_function = $this->getSetting('allowed_values_function');
 
@@ -117,11 +118,11 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
    *   An associative array containing the properties and children of the
    *   generic form element.
    * @param $form_state
-   *   The $form_state array for the form this element belongs to.
+   *   The current state of the form for the form this element belongs to.
    *
    * @see form_process_pattern()
    */
-  public static function validateAllowedValues($element, &$form_state) {
+  public static function validateAllowedValues($element, FormStateInterface $form_state) {
     $values = static::extractAllowedValues($element['#value'], $element['#field_has_data']);
 
     if (!is_array($values)) {
diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php
index fa56329..aed9a29 100644
--- a/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php
+++ b/core/modules/options/src/Plugin/Field/FieldWidget/ButtonsWidget.php
@@ -8,6 +8,7 @@
 namespace Drupal\options\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'options_buttons' widget.
@@ -29,7 +30,7 @@ class ButtonsWidget extends OptionsWidgetBase {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element = parent::formElement($items, $delta, $element, $form, $form_state);
 
     $options = $this->getOptions($items[$delta]);
diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php
index 01e7688..9f1e014 100644
--- a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldItemInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Base class for the 'options_*' widgets.
@@ -54,7 +55,7 @@ public function __construct($plugin_id, $plugin_definition, FieldDefinitionInter
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     // Prepare some properties for the child methods to build the actual form
     // element.
     $this->required = $element['#required'];
@@ -75,10 +76,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
    *
    * @param array $element
    *   The form element.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public static function validateElement(array $element, array &$form_state) {
+  public static function validateElement(array $element, FormStateInterface $form_state) {
     if ($element['#required'] && $element['#value'] == '_none') {
       \Drupal::formBuilder()->setError($element, $form_state, t('!name field is required.', array('!name' => $element['#title'])));
     }
diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php
index 6d37440..093e06c 100644
--- a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php
+++ b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php
@@ -8,6 +8,7 @@
 namespace Drupal\options\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\options\Plugin\Field\FieldWidget\OptionsWidgetBase;
 
 /**
@@ -29,7 +30,7 @@ class SelectWidget extends OptionsWidgetBase {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element = parent::formElement($items, $delta, $element, $form, $form_state);
 
     $element += array(
diff --git a/core/modules/path/src/Form/DeleteForm.php b/core/modules/path/src/Form/DeleteForm.php
index c669a1f..b253490 100644
--- a/core/modules/path/src/Form/DeleteForm.php
+++ b/core/modules/path/src/Form/DeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\path\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Path\AliasStorageInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -72,9 +73,9 @@ public function getCancelUrl() {
   }
 
   /**
-   * Overrides \Drupal\Core\Form\ConfirmFormBase::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $pid = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
     $this->pathAlias = $this->aliasStorage->load(array('pid' => $pid));
 
     $form = parent::buildForm($form, $form_state);
@@ -83,9 +84,9 @@ public function buildForm(array $form, array &$form_state, $pid = NULL) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->aliasStorage->delete(array('pid' => $this->pathAlias['pid']));
 
     $form_state['redirect'] = 'admin/config/search/path';
diff --git a/core/modules/path/src/Form/EditForm.php b/core/modules/path/src/Form/EditForm.php
index 0c1a7ab..b5fd90e 100644
--- a/core/modules/path/src/Form/EditForm.php
+++ b/core/modules/path/src/Form/EditForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\path\Form;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -32,7 +33,7 @@ protected function buildPath($pid) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $pid = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
     $form = parent::buildForm($form, $form_state, $pid);
 
     $form['#title'] = String::checkPlain($this->path['alias']);
@@ -51,7 +52,7 @@ public function buildForm(array $form, array &$form_state, $pid = NULL) {
   /**
    * Submits the delete form.
    */
-  public function deleteSubmit(array &$form, array &$form_state) {
+  public function deleteSubmit(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = new Url('path.delete', array(
       'pid' => $form_state['values']['pid'],
     ));
diff --git a/core/modules/path/src/Form/PathFilterForm.php b/core/modules/path/src/Form/PathFilterForm.php
index ce66c70..e8130f0 100644
--- a/core/modules/path/src/Form/PathFilterForm.php
+++ b/core/modules/path/src/Form/PathFilterForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\path\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $keys = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $keys = NULL) {
     $form['#attributes'] = array('class' => array('search-form'));
     $form['basic'] = array(
       '#type' => 'details',
@@ -59,7 +60,7 @@ public function buildForm(array $form, array &$form_state, $keys = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = new Url('path.admin_overview_filter', array(
       'keys' => trim($form_state['values']['filter']),
     ));
@@ -68,7 +69,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Resets the filter selections.
    */
-  public function resetForm(array &$form, array &$form_state) {
+  public function resetForm(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = new Url('path.admin_overview');
   }
 
diff --git a/core/modules/path/src/Form/PathFormBase.php b/core/modules/path/src/Form/PathFormBase.php
index a9e80c4..f4d7ffd 100644
--- a/core/modules/path/src/Form/PathFormBase.php
+++ b/core/modules/path/src/Form/PathFormBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\path\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Path\AliasManagerInterface;
 use Drupal\Core\Path\AliasStorageInterface;
@@ -74,7 +75,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $pid = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $pid = NULL) {
     $this->path = $this->buildPath($pid);
     $form['source'] = array(
       '#type' => 'textfield',
@@ -135,7 +136,7 @@ public function buildForm(array $form, array &$form_state, $pid = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $source = &$form_state['values']['source'];
     $source = $this->aliasManager->getPathByAlias($source);
     $alias = $form_state['values']['alias'];
@@ -154,7 +155,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Remove unnecessary values.
     form_state_values_clean($form_state);
 
diff --git a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
index d090022..dc4d256 100644
--- a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
+++ b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
@@ -28,7 +29,7 @@ class PathWidget extends WidgetBase {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $entity = $items->getEntity();
     $path = array();
     if (!$entity->isNew()) {
@@ -79,10 +80,10 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
    *
    * @param array $element
    *   The form element.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state.
    */
-  public static function validateFormElement(array &$element, array &$form_state) {
+  public static function validateFormElement(array &$element, FormStateInterface $form_state) {
     // Trim the submitted value.
     $alias = trim($element['alias']['#value']);
     if (!empty($alias)) {
@@ -100,7 +101,7 @@ public static function validateFormElement(array &$element, array &$form_state)
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     return $element['alias'];
   }
 
diff --git a/core/modules/quickedit/src/Form/QuickEditFieldForm.php b/core/modules/quickedit/src/Form/QuickEditFieldForm.php
index 38b82a5..6ce51d8 100644
--- a/core/modules/quickedit/src/Form/QuickEditFieldForm.php
+++ b/core/modules/quickedit/src/Form/QuickEditFieldForm.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityChangedInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\entity\Entity\EntityFormDisplay;
 use Drupal\user\TempStoreFactory;
@@ -83,7 +84,7 @@ public function getFormId() {
    *
    * Builds a form for a single entity field.
    */
-  public function buildForm(array $form, array &$form_state, EntityInterface $entity = NULL, $field_name = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $field_name = NULL) {
     if (!isset($form_state['entity'])) {
       $this->init($form_state, $entity, $field_name);
     }
@@ -116,7 +117,7 @@ public function buildForm(array $form, array &$form_state, EntityInterface $enti
   /**
    * Initialize the form state and the entity before the first form build.
    */
-  protected function init(array &$form_state, EntityInterface $entity, $field_name) {
+  protected function init(FormStateInterface $form_state, EntityInterface $entity, $field_name) {
     // @todo Rather than special-casing $node->revision, invoke prepareEdit()
     //   once http://drupal.org/node/1863258 lands.
     if ($entity->getEntityTypeId() == 'node') {
@@ -143,7 +144,7 @@ protected function init(array &$form_state, EntityInterface $entity, $field_name
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $entity = $this->buildEntity($form, $form_state);
 
     $form_state['form_display']->validateFormValues($entity, $form, $form_state);
@@ -164,7 +165,7 @@ public function validateForm(array &$form, array &$form_state) {
    *
    * Saves the entity with updated values for the edited field.
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['entity'] = $this->buildEntity($form, $form_state);
 
     // Store entity in tempstore with its UUID as tempstore key.
@@ -177,7 +178,7 @@ public function submitForm(array &$form, array &$form_state) {
    * Calling code may then validate the returned entity, and if valid, transfer
    * it back to the form state and save it.
    */
-  protected function buildEntity(array $form, array &$form_state) {
+  protected function buildEntity(array $form, FormStateInterface $form_state) {
     /** @var $entity \Drupal\Core\Entity\EntityInterface */
     $entity = clone $form_state['entity'];
     $field_name = $form_state['field_name'];
@@ -203,10 +204,10 @@ protected function buildEntity(array $form, array &$form_state) {
    *
    * @param array &$form
    *   A reference to an associative array containing the structure of the form.
-   * @param array &$form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  protected function simplify(array &$form, array &$form_state) {
+  protected function simplify(array &$form, FormStateInterface $form_state) {
     $field_name = $form_state['field_name'];
     $widget_element =& $form[$field_name]['widget'];
 
diff --git a/core/modules/quickedit/src/QuickEditController.php b/core/modules/quickedit/src/QuickEditController.php
index 2c1c093..ad1751d 100644
--- a/core/modules/quickedit/src/QuickEditController.php
+++ b/core/modules/quickedit/src/QuickEditController.php
@@ -8,6 +8,7 @@
 namespace Drupal\quickedit;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Form\FormState;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
@@ -177,13 +178,13 @@ public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view
       $this->tempStoreFactory->get('quickedit')->set($entity->uuid(), $entity);
     }
 
-    $form_state = array(
+    $form_state = new FormState(array(
       'langcode' => $langcode,
       'no_redirect' => TRUE,
       'build_info' => array(
         'args' => array($entity, $field_name),
       ),
-    );
+    ));
     $form = $this->formBuilder()->buildForm('Drupal\quickedit\Form\QuickEditFieldForm', $form_state);
 
     if (!empty($form_state['executed'])) {
diff --git a/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php b/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php
index bd30ea3..e614e0e 100644
--- a/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php
+++ b/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\responsive_image\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 class ResponsiveImageMappingDeleteForm extends EntityConfirmFormBase {
@@ -36,7 +37,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message($this->t('Responsive image mapping %label has been deleted.', array('%label' => $this->entity->label())));
     watchdog('responsive_image', 'Responsive image mapping %label has been deleted.', array('%label' => $this->entity->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
index ad4723f..24a80d4 100644
--- a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
+++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatterBase;
 
 /**
@@ -38,7 +39,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $responsive_image_options = array();
     $responsive_image_mappings = entity_load_multiple('responsive_image_mapping');
     if ($responsive_image_mappings && !empty($responsive_image_mappings)) {
diff --git a/core/modules/responsive_image/src/ResponsiveImageMappingForm.php b/core/modules/responsive_image/src/ResponsiveImageMappingForm.php
index 57779fd..7a38d12 100644
--- a/core/modules/responsive_image/src/ResponsiveImageMappingForm.php
+++ b/core/modules/responsive_image/src/ResponsiveImageMappingForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for the responsive image edit/add forms.
@@ -20,15 +21,15 @@ class ResponsiveImageMappingForm extends EntityForm {
    *
    * @param array $form
    *   A nested array form elements comprising the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\responsive_image\ResponsiveImageMappingInterface $responsive_image_mapping
    *   The entity being edited.
    *
    * @return array
    *   The array containing the complete form.
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     if ($this->operation == 'duplicate') {
       $form['#title'] = $this->t('<em>Duplicate responsive image mapping</em> @label', array('@label' => $this->entity->label()));
       $this->entity = $this->entity->createDuplicate();
@@ -96,7 +97,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\responsive_image\ResponsiveImageMappingInterface $responsive_image_mapping */
     $responsive_image_mapping = $this->entity;
 
@@ -119,7 +120,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::save().
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\responsive_image\ResponsiveImageMappingInterface $responsive_image_mapping */
     $responsive_image_mapping = $this->entity;
     $responsive_image_mapping->save();
diff --git a/core/modules/rest/src/Plugin/views/row/DataFieldRow.php b/core/modules/rest/src/Plugin/views/row/DataFieldRow.php
index b3896a1..68668ba 100644
--- a/core/modules/rest/src/Plugin/views/row/DataFieldRow.php
+++ b/core/modules/rest/src/Plugin/views/row/DataFieldRow.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\rest\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\row\RowPluginBase;
@@ -74,7 +75,7 @@ protected function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['field_options'] = array(
@@ -111,7 +112,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Form element validation handler for \Drupal\rest\Plugin\views\row\DataFieldRow::buildOptionsForm().
    */
-  public function validateAliasName($element, &$form_state) {
+  public function validateAliasName($element, FormStateInterface $form_state) {
     if (preg_match('@[^A-Za-z0-9_-]+@', $element['#value'])) {
       form_error($element, $form_state, t('The machine-readable name must contain only letters, numbers, dashes and underscores.'));
     }
@@ -120,7 +121,7 @@ public function validateAliasName($element, &$form_state) {
   /**
    * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::validateOptionsForm().
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     // Collect an array of aliases to validate.
     $aliases = static::extractFromOptionsArray('alias', $form_state['values']['row_options']['field_options']);
 
diff --git a/core/modules/rest/src/Plugin/views/style/Serializer.php b/core/modules/rest/src/Plugin/views/style/Serializer.php
index 1403dc3..6652963 100644
--- a/core/modules/rest/src/Plugin/views/style/Serializer.php
+++ b/core/modules/rest/src/Plugin/views/style/Serializer.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\rest\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\style\StylePluginBase;
@@ -88,7 +89,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['formats'] = array(
@@ -103,7 +104,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
 
     $form_state['values']['style_options']['formats'] = array_filter($form_state['values']['style_options']['formats']);
diff --git a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_entity.yml b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_entity.yml
index 98ec072..687f3f2 100644
--- a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_entity.yml
+++ b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_entity.yml
@@ -40,6 +40,7 @@ display:
     id: rest_export_1
     display_title: serializer
     position: null
+    provider: rest
     display_options:
       defaults:
         access: false
@@ -48,3 +49,6 @@ base_field: id
 status: true
 module: rest
 langcode: und
+dependencies:
+  module:
+    - rest
diff --git a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_field.yml b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_field.yml
index 33f6c94..9a85fb8 100644
--- a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_field.yml
+++ b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_display_field.yml
@@ -68,6 +68,7 @@ display:
     id: rest_export_1
     display_title: serializer
     position: null
+    provider: rest
     display_options:
       defaults:
         access: false
@@ -85,6 +86,7 @@ display:
     id: rest_export_2
     display_title: 'serialize - access denied'
     position: null
+    provider: rest
     display_options:
       defaults:
         access: false
@@ -103,3 +105,6 @@ base_field: id
 status: true
 module: rest
 langcode: und
+dependencies:
+  module:
+    - rest
diff --git a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_node_display_field.yml b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_node_display_field.yml
index aa44af0..41c8241 100644
--- a/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_node_display_field.yml
+++ b/core/modules/rest/tests/modules/rest_test_views/test_views/views.view.test_serializer_node_display_field.yml
@@ -102,6 +102,7 @@ display:
     id: rest_export_1
     display_title: serializer
     position: null
+    provider: rest
     display_options:
       defaults:
         access: false
@@ -118,3 +119,6 @@ base_field: nid
 status: true
 module: rest_test_views
 langcode: und
+dependencies:
+  module:
+    - rest
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 59646f9..be8da8a 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -831,7 +832,7 @@ function search_module_preinstall() {
  *
  * @see \Drupal\search\Form\SearchBlockForm
  */
-function search_form_search_block_form_alter(&$form, &$form_state) {
+function search_form_search_block_form_alter(&$form, FormStateInterface $form_state) {
   $form['form_build_id']['#access'] = FALSE;
   $form['form_token']['#access'] = FALSE;
   $form['form_id']['#access'] = FALSE;
diff --git a/core/modules/search/src/Form/ReindexConfirm.php b/core/modules/search/src/Form/ReindexConfirm.php
index e83e8c0..06c457b 100644
--- a/core/modules/search/src/Form/ReindexConfirm.php
+++ b/core/modules/search/src/Form/ReindexConfirm.php
@@ -8,6 +8,7 @@
 namespace Drupal\search\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -58,9 +59,9 @@ public function getCancelUrl() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($form['confirm']) {
       search_reindex();
       drupal_set_message($this->t('The index will be rebuilt.'));
diff --git a/core/modules/search/src/Form/SearchBlockForm.php b/core/modules/search/src/Form/SearchBlockForm.php
index dafe312..e154863 100644
--- a/core/modules/search/src/Form/SearchBlockForm.php
+++ b/core/modules/search/src/Form/SearchBlockForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\search\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\search\SearchPageRepositoryInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -52,7 +53,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Set up the form to submit using GET to the correct search page.
     $entity_id = $this->searchPageRepository->getDefaultSearchPage();
     if (!$entity_id) {
@@ -90,7 +91,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // This form submits to the search page, so processing happens there.
   }
 }
diff --git a/core/modules/search/src/Form/SearchPageAddForm.php b/core/modules/search/src/Form/SearchPageAddForm.php
index c8f3f68..0550f74 100644
--- a/core/modules/search/src/Form/SearchPageAddForm.php
+++ b/core/modules/search/src/Form/SearchPageAddForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\search\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a form for adding a search page.
  */
@@ -15,7 +17,7 @@ class SearchPageAddForm extends SearchPageFormBase {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $search_plugin_id = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $search_plugin_id = NULL) {
     $this->entity->setPlugin($search_plugin_id);
     $definition = $this->entity->getPlugin()->getPluginDefinition();
     $this->entity->set('label', $definition['title']);
@@ -25,7 +27,7 @@ public function buildForm(array $form, array &$form_state, $search_plugin_id = N
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Add search page');
     return $actions;
@@ -34,7 +36,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     // If there is no default search page, make the added search the default.
     if (!$this->searchPageRepository->getDefaultSearchPage()) {
       $this->searchPageRepository->setDefaultSearchPage($this->entity);
diff --git a/core/modules/search/src/Form/SearchPageDeleteForm.php b/core/modules/search/src/Form/SearchPageDeleteForm.php
index 5727649..a78d1c2 100644
--- a/core/modules/search/src/Form/SearchPageDeleteForm.php
+++ b/core/modules/search/src/Form/SearchPageDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\search\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     $form_state['redirect_route'] = $this->getCancelUrl();
     drupal_set_message($this->t('The %label search page has been deleted.', array('%label' => $this->entity->label())));
diff --git a/core/modules/search/src/Form/SearchPageEditForm.php b/core/modules/search/src/Form/SearchPageEditForm.php
index dc3de86..7ff9260 100644
--- a/core/modules/search/src/Form/SearchPageEditForm.php
+++ b/core/modules/search/src/Form/SearchPageEditForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\search\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a form for editing a search page.
  */
@@ -15,7 +17,7 @@ class SearchPageEditForm extends SearchPageFormBase {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Save search page');
     return $actions;
@@ -24,7 +26,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     parent::save($form, $form_state);
 
     drupal_set_message($this->t('The %label search page has been updated.', array('%label' => $this->entity->label())));
diff --git a/core/modules/search/src/Form/SearchPageForm.php b/core/modules/search/src/Form/SearchPageForm.php
index 1dac382..8e585db 100644
--- a/core/modules/search/src/Form/SearchPageForm.php
+++ b/core/modules/search/src/Form/SearchPageForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\search\Form;
 
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a search form for site wide search.
@@ -37,7 +38,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $plugin = $this->entity->getPlugin();
     $form_state['search_page_id'] = $this->entity->id();
 
@@ -74,7 +75,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     // The submit button is added in the form directly.
     return array();
   }
@@ -82,7 +83,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Redirect to the search page with keywords in the GET parameters.
     // Plugins with additional search parameters will need to provide their
     // own form submit handler to replace this, so they can put their values
diff --git a/core/modules/search/src/Form/SearchPageFormBase.php b/core/modules/search/src/Form/SearchPageFormBase.php
index 45e5cd4..97cd2fc 100644
--- a/core/modules/search/src/Form/SearchPageFormBase.php
+++ b/core/modules/search/src/Form/SearchPageFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\search\SearchPageRepositoryInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -79,7 +80,7 @@ public function getBaseFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $this->plugin = $this->entity->getPlugin();
     return parent::buildForm($form, $form_state);
   }
@@ -87,7 +88,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['label'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('Label'),
@@ -143,7 +144,7 @@ public function exists($id) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     // Ensure each path is unique.
@@ -163,7 +164,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     if ($this->plugin instanceof PluginFormInterface) {
@@ -175,7 +176,7 @@ public function submit(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $this->entity->save();
 
     $form_state['redirect_route']['route_name'] = 'search.settings';
diff --git a/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php b/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php
index 8dcc9a4..d5de0c4 100644
--- a/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php
+++ b/core/modules/search/src/Plugin/ConfigurableSearchPluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\search\Plugin;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a base implementation for a configurable Search plugin.
@@ -54,7 +55,7 @@ public function setConfiguration(array $configuration) {
   /**
    * {@inheritdoc}
    */
-  public function validateConfigurationForm(array &$form, array &$form_state) {
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
diff --git a/core/modules/search/src/Plugin/SearchInterface.php b/core/modules/search/src/Plugin/SearchInterface.php
index 144c0ab..34c9d4f 100644
--- a/core/modules/search/src/Plugin/SearchInterface.php
+++ b/core/modules/search/src/Plugin/SearchInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\search\Plugin;
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a common interface for all SearchPlugin objects.
@@ -91,14 +92,14 @@ public function buildResults();
    *
    * @param array $form
    *   Nested array of form elements that comprise the form.
-   * @param array $form_state
-   *   A keyed array containing the current state of the form. The arguments
-   *   that \Drupal::formBuilder()->getForm() was originally called with are
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form. The arguments that
+   *   \Drupal::formBuilder()->getForm() was originally called with are
    *   available in the array $form_state['build_info']['args'].
    *
    * @see SearchInterface::buildSearchUrlQuery()
    */
-  public function searchFormAlter(array &$form, array &$form_state);
+  public function searchFormAlter(array &$form, FormStateInterface $form_state);
 
   /**
    * Builds the URL GET query parameters array for search.
@@ -108,7 +109,7 @@ public function searchFormAlter(array &$form, array &$form_state);
    * method to add form elements to the search form will need to override this
    * method to gather the form input and add it to the GET query parameters.
    *
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state, with submitted form information.
    *
    * @return array
diff --git a/core/modules/search/src/Plugin/SearchPluginBase.php b/core/modules/search/src/Plugin/SearchPluginBase.php
index e13a307..9a553cc 100644
--- a/core/modules/search/src/Plugin/SearchPluginBase.php
+++ b/core/modules/search/src/Plugin/SearchPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\search\Plugin;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -104,7 +105,7 @@ public function buildResults() {
   /**
    * {@inheritdoc}
    */
-  public function searchFormAlter(array &$form, array &$form_state) {
+  public function searchFormAlter(array &$form, FormStateInterface $form_state) {
     // Empty default implementation.
   }
 
diff --git a/core/modules/search/src/Plugin/views/filter/Search.php b/core/modules/search/src/Plugin/views/filter/Search.php
index ef69c7d..e885ce9 100644
--- a/core/modules/search/src/Plugin/views/filter/Search.php
+++ b/core/modules/search/src/Plugin/views/filter/Search.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\search\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
@@ -70,7 +71,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  protected function operatorForm(&$form, &$form_state) {
+  protected function operatorForm(&$form, FormStateInterface $form_state) {
     $form['operator'] = array(
       '#type' => 'radios',
       '#title' => t('On empty input'),
@@ -85,7 +86,7 @@ protected function operatorForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     $form['value'] = array(
       '#type' => 'textfield',
       '#size' => 15,
@@ -98,7 +99,7 @@ protected function valueForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateExposed(&$form, &$form_state) {
+  public function validateExposed(&$form, FormStateInterface $form_state) {
     if (!isset($this->options['expose']['identifier'])) {
       return;
     }
diff --git a/core/modules/search/src/Plugin/views/row/SearchRow.php b/core/modules/search/src/Plugin/views/row/SearchRow.php
index 8c0709f..c93efda 100644
--- a/core/modules/search/src/Plugin/views/row/SearchRow.php
+++ b/core/modules/search/src/Plugin/views/row/SearchRow.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\search\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\RowPluginBase;
 
 /**
@@ -34,7 +35,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['score'] = array(
       '#type' => 'checkbox',
       '#title' => t('Display score'),
diff --git a/core/modules/search/src/SearchPageListBuilder.php b/core/modules/search/src/SearchPageListBuilder.php
index d6a837a..ac40476 100644
--- a/core/modules/search/src/SearchPageListBuilder.php
+++ b/core/modules/search/src/SearchPageListBuilder.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -152,7 +153,7 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
     $old_state = $this->configFactory->getOverrideState();
     $search_settings = $this->configFactory->setOverrideState(FALSE)->get('search.settings');
@@ -318,13 +319,13 @@ public function getDefaultOperations(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     $search_settings = $this->configFactory->get('search.settings');
@@ -348,7 +349,7 @@ public function submitForm(array &$form, array &$form_state) {
    * Form submission handler for the reindex button on the search admin settings
    * form.
    */
-  public function searchAdminReindexSubmit(array &$form, array &$form_state) {
+  public function searchAdminReindexSubmit(array &$form, FormStateInterface $form_state) {
     // Send the user to the confirmation page.
     $form_state['redirect_route']['route_name'] = 'search.reindex_confirm';
   }
@@ -356,7 +357,7 @@ public function searchAdminReindexSubmit(array &$form, array &$form_state) {
   /**
    * Form validation handler for adding a new search page.
    */
-  public function validateAddSearchPage(array &$form, array &$form_state) {
+  public function validateAddSearchPage(array &$form, FormStateInterface $form_state) {
     if (empty($form_state['values']['search_type'])) {
       $this->formBuilder()->setErrorByName('search_type', $form_state, $this->t('You must select the new search page type.'));
     }
@@ -365,7 +366,7 @@ public function validateAddSearchPage(array &$form, array &$form_state) {
   /**
    * Form submission handler for adding a new search page.
    */
-  public function submitAddSearchPage(array &$form, array &$form_state) {
+  public function submitAddSearchPage(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = array(
       'route_name' => 'search.add_type',
       'route_parameters' => array(
diff --git a/core/modules/search/tests/modules/search_embedded_form/src/Form/SearchEmbeddedForm.php b/core/modules/search/tests/modules/search_embedded_form/src/Form/SearchEmbeddedForm.php
index d0d690d..3bb04e0 100644
--- a/core/modules/search/tests/modules/search_embedded_form/src/Form/SearchEmbeddedForm.php
+++ b/core/modules/search/tests/modules/search_embedded_form/src/Form/SearchEmbeddedForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\search_embedded_form\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for search_embedded_form form.
@@ -24,7 +25,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $count = \Drupal::state()->get('search_embedded_form.submit_count');
 
     $form['name'] = array(
@@ -48,7 +49,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $state = \Drupal::state();
     $submit_count = (int) $state->get('search_embedded_form.submit_count');
     $state->set('search_embedded_form.submit_count', $submit_count + 1);
diff --git a/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php b/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php
index 32cfb77..2c34010 100644
--- a/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php
+++ b/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php
@@ -8,6 +8,7 @@
 namespace Drupal\search_extra_type\Plugin\Search;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\search\Plugin\ConfigurableSearchPluginBase;
 
 /**
@@ -89,7 +90,7 @@ public function buildResults() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     // Output form for defining rank factor weights.
     $form['extra_type_settings'] = array(
       '#type' => 'fieldset',
@@ -112,7 +113,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['boost'] = $form_state['values']['extra_type_settings']['boost'];
   }
 
diff --git a/core/modules/shortcut/src/Form/SetCustomize.php b/core/modules/shortcut/src/Form/SetCustomize.php
index a306f50..d6afd90 100644
--- a/core/modules/shortcut/src/Form/SetCustomize.php
+++ b/core/modules/shortcut/src/Form/SetCustomize.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -27,7 +28,7 @@ class SetCustomize extends EntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
     $form['shortcuts'] = array(
       '#tree' => TRUE,
@@ -82,7 +83,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     // Only includes a Save action for the entity, no direct Delete button.
     return array(
       'submit' => array(
@@ -99,7 +100,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     foreach ($this->entity->getShortcuts() as $shortcut) {
       $shortcut->setWeight($form_state['values']['shortcuts']['links'][$shortcut->id()]['weight']);
       $shortcut->save();
diff --git a/core/modules/shortcut/src/Form/ShortcutDeleteForm.php b/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
index bef1c00..0256017 100644
--- a/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
+++ b/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\shortcut\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -48,7 +49,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     $form_state['redirect_route'] = $this->getCancelUrl();
     drupal_set_message($this->t('The shortcut %title has been deleted.', array('%title' => $this->entity->title->value)));
diff --git a/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php b/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php
index 14f20f2..f7e28ac 100644
--- a/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php
+++ b/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\shortcut\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\shortcut\ShortcutSetStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -74,7 +75,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Find out how many users are directly assigned to this shortcut set, and
     // make a message.
     $number = $this->storage->countAssignedUsers($this->entity);
@@ -101,7 +102,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     $form_state['redirect_route'] = new Url('shortcut.set_admin');
     drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $this->entity->label())));
diff --git a/core/modules/shortcut/src/Form/SwitchShortcutSet.php b/core/modules/shortcut/src/Form/SwitchShortcutSet.php
index ec3180c..a66a890 100644
--- a/core/modules/shortcut/src/Form/SwitchShortcutSet.php
+++ b/core/modules/shortcut/src/Form/SwitchShortcutSet.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Access\AccessInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\shortcut\Entity\ShortcutSet;
 use Drupal\shortcut\ShortcutSetStorageInterface;
@@ -75,7 +76,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, UserInterface $user = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, UserInterface $user = NULL) {
     $account = $this->currentUser();
 
     $this->user = $user;
@@ -169,7 +170,7 @@ public function exists($id) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['set'] == 'new') {
       // Check to prevent creating a shortcut set with an empty title.
       if (trim($form_state['values']['label']) == '') {
@@ -185,7 +186,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $account = $this->currentUser();
 
     $account_is_user = $this->user->id() == $account->id();
diff --git a/core/modules/shortcut/src/ShortcutForm.php b/core/modules/shortcut/src/ShortcutForm.php
index 33c169a..e36fd79 100644
--- a/core/modules/shortcut/src/ShortcutForm.php
+++ b/core/modules/shortcut/src/ShortcutForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\shortcut;
 
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
@@ -25,7 +26,7 @@ class ShortcutForm extends ContentEntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $form['path'] = array(
@@ -50,7 +51,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     $entity = parent::buildEntity($form, $form_state);
 
     // Set the computed 'path' value so it can used in the preSave() method to
@@ -63,7 +64,7 @@ public function buildEntity(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     if (!shortcut_valid_link($form_state['values']['path'])) {
       $this->setFormError('path', $form_state, $this->t('The shortcut must correspond to a valid path on the site.'));
     }
@@ -74,7 +75,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
     $entity->save();
 
diff --git a/core/modules/shortcut/src/ShortcutSetForm.php b/core/modules/shortcut/src/ShortcutSetForm.php
index 2b50ed2..be48569 100644
--- a/core/modules/shortcut/src/ShortcutSetForm.php
+++ b/core/modules/shortcut/src/ShortcutSetForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\shortcut;
 
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for the shortcut set entity edit forms.
@@ -17,7 +18,7 @@ class ShortcutSetForm extends EntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $entity = $this->entity;
@@ -50,7 +51,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
     $entity = $this->entity;
     // Check to prevent a duplicate title.
@@ -62,7 +63,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
     $is_new = !$entity->getOriginalId();
     $entity->save();
diff --git a/core/modules/simpletest/src/Form/SimpletestResultsForm.php b/core/modules/simpletest/src/Form/SimpletestResultsForm.php
index e2b4960..f9e48d3 100644
--- a/core/modules/simpletest/src/Form/SimpletestResultsForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestResultsForm.php
@@ -10,6 +10,8 @@
 use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\simpletest\TestDiscovery;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -103,7 +105,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $test_id = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $test_id = NULL) {
     $this->buildStatusImageMap();
     // Make sure there are test results to display and a re-run is not being
     // performed.
@@ -249,7 +251,7 @@ public function buildForm(array $form, array &$form_state, $test_id = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $pass = $form_state['values']['filter_pass'] ? explode(',', $form_state['values']['filter_pass']) : array();
     $fail = $form_state['values']['filter_fail'] ? explode(',', $form_state['values']['filter_fail']) : array();
 
@@ -269,7 +271,7 @@ public function submitForm(array &$form, array &$form_state) {
     }
 
     $form_execute = array();
-    $form_state_execute = array('values' => array());
+    $form_state_execute = new FormState(array('values' => array()));
     foreach ($classes as $class) {
       $form_state_execute['values']['tests'][$class] = $class;
     }
diff --git a/core/modules/simpletest/src/Form/SimpletestSettingsForm.php b/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
index 563b05d..2b1e71d 100644
--- a/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\simpletest\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure simpletest settings for this site.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('simpletest.settings');
     $form['general'] = array(
       '#type' => 'details',
@@ -86,7 +87,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $config = $this->config('simpletest.settings');
     // If a username was provided but a password wasn't, preserve the existing
     // password.
@@ -106,7 +107,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('simpletest.settings')
       ->set('clear_results', $form_state['values']['simpletest_clear_results'])
       ->set('verbose', $form_state['values']['simpletest_verbose'])
diff --git a/core/modules/simpletest/src/Form/SimpletestTestForm.php b/core/modules/simpletest/src/Form/SimpletestTestForm.php
index ab9b55e..bb56b69 100644
--- a/core/modules/simpletest/src/Form/SimpletestTestForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestTestForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * List tests arranged in groups that can be selected and run.
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array(
       '#type' => 'submit',
@@ -183,7 +184,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Test discovery does not run upon form submission.
     simpletest_classloader_register();
 
diff --git a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
index 69e4235..288cf4d 100644
--- a/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
+++ b/core/modules/simpletest/src/Tests/KernelTestBaseTest.php
@@ -214,7 +214,7 @@ function testInstallConfig() {
    */
   function testEnableModulesFixedList() {
     // Install system module.
-    $this->container->get('module_handler')->install(array('system', 'menu_link'));
+    $this->container->get('module_handler')->install(array('system', 'menu_link_content'));
     $entity_manager = \Drupal::entityManager();
 
     // entity_test is loaded via $modules; its entity type should exist.
diff --git a/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php b/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php
index 3bdacac..62745b7 100644
--- a/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php
+++ b/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php
@@ -8,6 +8,7 @@
 namespace Drupal\statistics\Plugin\Block;
 
 use Drupal\block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -75,9 +76,9 @@ protected function blockAccess(AccountInterface $account) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockForm().
+   * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     // Popular content block settings.
     $numbers = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40);
     $numbers = array('0' => t('Disabled')) + array_combine($numbers, $numbers);
@@ -106,9 +107,9 @@ public function blockForm($form, &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\block\BlockBase::blockSubmit().
+   * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['top_day_num'] = $form_state['values']['statistics_block_top_day_num'];
     $this->configuration['top_all_num'] = $form_state['values']['statistics_block_top_all_num'];
     $this->configuration['top_last_num'] = $form_state['values']['statistics_block_top_last_num'];
diff --git a/core/modules/statistics/src/StatisticsSettingsForm.php b/core/modules/statistics/src/StatisticsSettingsForm.php
index c002590..cac15a1 100644
--- a/core/modules/statistics/src/StatisticsSettingsForm.php
+++ b/core/modules/statistics/src/StatisticsSettingsForm.php
@@ -9,6 +9,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -55,9 +56,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('statistics.settings');
 
     // Content counter settings.
@@ -77,9 +78,9 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('statistics.settings')
       ->set('count_content_views', $form_state['values']['statistics_count_content_views'])
       ->save();
diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module
index 4165fab..baee84f 100644
--- a/core/modules/syslog/syslog.module
+++ b/core/modules/syslog/syslog.module
@@ -5,6 +5,7 @@
  * Redirects logging messages to syslog.
  */
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
@@ -30,7 +31,7 @@ function syslog_help($route_name, RouteMatchInterface $route_match) {
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function syslog_form_system_logging_settings_alter(&$form, &$form_state) {
+function syslog_form_system_logging_settings_alter(&$form, FormStateInterface $form_state) {
   $config = \Drupal::config('syslog.settings');
   $help = \Drupal::moduleHandler()->moduleExists('help') ? ' ' . l(t('More information'), 'admin/help/syslog') . '.' : NULL;
   $form['syslog_identity'] = array(
@@ -63,7 +64,7 @@ function syslog_form_system_logging_settings_alter(&$form, &$form_state) {
  *
  * @see syslog_form_system_logging_settings_alter()
  */
-function syslog_logging_settings_submit($form, &$form_state) {
+function syslog_logging_settings_submit($form, FormStateInterface $form_state) {
   \Drupal::config('syslog.settings')
     ->set('identity', $form_state['values']['syslog_identity'])
     ->set('facility', $form_state['values']['syslog_facility'])
diff --git a/core/modules/system/config/install/system.menu.yml b/core/modules/system/config/install/system.menu.yml
deleted file mode 100644
index e73636c..0000000
--- a/core/modules/system/config/install/system.menu.yml
+++ /dev/null
@@ -1 +0,0 @@
-active_menus_default: []
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index 5375524..2e9219d 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -168,17 +168,6 @@ system.logging:
       type: string
       label: 'Error messages to display'
 
-system.menu:
-  type: mapping
-  label: 'Menu settings'
-  mapping:
-    active_menus_default:
-      type: sequence
-      label: 'Active menus'
-      sequence:
-        - type: string
-          label: 'Menu'
-
 system.performance:
   type: mapping
   label: 'Performance settings'
diff --git a/core/modules/system/core.api.php b/core/modules/system/core.api.php
index e1b0d80..03a711c 100644
--- a/core/modules/system/core.api.php
+++ b/core/modules/system/core.api.php
@@ -342,346 +342,6 @@
  */
 
 /**
- * @defgroup entity_api Entity API
- * @{
- * Describes how to define and manipulate content and configuration entities.
- *
- * Entities, in Drupal, are objects that are used for persistent storage of
- * content and configuration information. See the
- * @link info_types Information types topic @endlink for an overview of the
- * different types of information, and the
- * @link config_api Configuration API topic @endlink for more about the
- * configuration API.
- *
- * Each entity is an instance of a particular "entity type". Some content entity
- * types have sub-types, which are known as "bundles", while for other entity
- * types, there is only a single bundle. For example, the Node content entity
- * type, which is used for the main content pages in Drupal, has bundles that
- * are known as "content types", while the User content type, which is used for
- * user accounts, has only one bundle.
- *
- * The sections below have more information about entities and the Entity API;
- * for more detailed information, see https://drupal.org/developing/api/entity
- *
- * @section define Defining an entity type
- * Entity types are defined by modules, using Drupal's Plugin API (see the
- * @link plugin_api Plugin API topic @endlink for more information about plugins
- * in general). Here are the steps to follow to define a new entity type:
- * - Choose a unique machine name, or ID, for your entity type. This normally
- *   starts with (or is the same as) your module's machine name. It should be
- *   as short as possible, and may not exceed 32 characters.
- * - Define an interface for your entity's get/set methods, extending either
- *   \Drupal\Core\Config\Entity\ConfigEntityInterface or
- *   \Drupal\Core\Entity\ContentEntityInterface.
- * - Define a class for your entity, implementing your interface and extending
- *   either \Drupal\Core\Config\Entity\ConfigEntityBase or
- *   \Drupal\Core\Entity\ContentEntityBase, with annotation for
- *   \@ConfigEntityType or \@ContentEntityType in its documentation block.
- * - The 'id' annotation gives the entity type ID, and the 'label' annotation
- *   gives the human-readable name of the entity type. If you are defining a
- *   content entity type that uses bundles, the 'bundle_label' annotation gives
- *   the human-readable name to use for a bundle of this entity type (for
- *   example, "Content type" for the Node entity).
- * - The annotation will refer to several controller classes, which you will
- *   also need to define:
- *   - list_builder: Define a class that extends
- *     \Drupal\Core\Config\Entity\ConfigEntityListBuilder (for configuration
- *     entities) or \Drupal\Core\Entity\EntityListBuilder (for content
- *     entities), to provide an administrative overview for your entities.
- *   - add and edit forms, or default form: Define a class (or two) that
- *     extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms
- *     for your entities. For content entities, base class
- *     \Drupal\Core\Entity\ContentEntityForm is a better starting point.
- *   - delete form: Define a class that extends
- *     \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete
- *     confirmation form for your entities.
- *   - view_builder: For content entities and config entities that need to be
- *     viewed, define a class that implements
- *     \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending
- *     \Drupal\Core\Entity\EntityViewBuilder), to display a single entity.
- *   - translation: For translatable content entities (if the 'translatable'
- *     annotation has value TRUE), define a class that extends
- *     \Drupal\content_translation\ContentTranslationHandler, to translate
- *     the content. Configuration translation is handled automatically by the
- *     Configuration Translation module, without the need of a controller class.
- *   - access: If your configuration entity has complex permissions, you might
- *     need an access controller, implementing
- *     \Drupal\Core\Entity\EntityAccessControllerInterface, but most entities
- *     can just use the 'admin_permission' annotation instead. Note that if you
- *     are creating your own access controller, you should override the
- *     checkAccess() and checkCreateAccess() methods, not access().
- *   - storage: A class implementing
- *     \Drupal\Core\Entity\EntityStorageInterface. If not specified, content
- *     entities will use \Drupal\Core\Entity\ContentEntityDatabaseStorage, and
- *     config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
- *     You can extend one of these classes to provide custom behavior.
- * - For content entities, the annotation will refer to a number of database
- *   tables and their fields. These annotation properties, such as 'base_table',
- *   'data_table', 'entity_keys', etc., are documented on
- *   \Drupal\Core\Entity\EntityType. Your module will also need to set up its
- *   database tables using hook_schema().
- * - For content entities that are displayed on their own pages, the annotation
- *   will refer to a 'uri_callback' function, which takes an object of the
- *   entity interface you have defined as its parameter, and returns routing
- *   information for the entity page; see node_uri() for an example. You will
- *   also need to add a corresponding route to your module's routing.yml file;
- *   see the node.view route in node.routing.yml for an example, and see
- *   @ref sec_routes below for some notes.
- * - Define routing and links for the various URLs associated with the entity.
- *   These go into the 'links' annotation, with the link type as the key, and
- *   the route machine name (defined in your module's routing.yml file) as the
- *   value; see @ref sec_routes below for some routing notes. Typical link
- *   types are:
- *   - canonical: Default link, either to view (if entities are viewed on their
- *     own pages) or edit the entity.
- *   - delete-form: Confirmation form to delete the entity.
- *   - edit-form: Editing form.
- *   - admin-form: Form for editing bundle or entity type settings.
- *   - Other link types specific to your entity type can also be defined.
- * - If your content entity has bundles, you will also need to define a second
- *   plugin to handle the bundles. This plugin is itself a configuration entity
- *   type, so follow the steps here to define it. The machine name ('id'
- *   annotation) of this configuration entity class goes into the
- *   'bundle_entity_type' annotation on the entity type class. For example, for
- *   the Node entity, the bundle class is \Drupal\node\Entity\NodeType, whose
- *   machine name is 'node_type'. This is the annotation value for
- *   'bundle_entity_type' on the \Drupal\node\Entity\Node class. Also, the
- *   bundle config entity type annotation must have a 'bundle_of' entry,
- *   giving the machine name of the entity type it is acting as a bundle for.
- * - Additional annotations can be seen on entity class examples such as
- *   \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
- *   (configuration). These annotations are documented on
- *   \Drupal\Core\Entity\EntityType.
- *
- * @section sec_routes Entity routes
- * Entity routes, like other routes, are defined in *.routing.yml files; see
- * the @link menu Menu and routing @endlink topic for more information. Here
- * is a typical entry, for the block configure form:
- * @code
- * block.admin_edit:
- *   path: '/admin/structure/block/manage/{block}'
- *   defaults:
- *     _entity_form: 'block.default'
- *     _title: 'Configure block'
- *   requirements:
- *     _entity_access: 'block.update'
- * @endcode
- * Some notes:
- * - path: The {block} in the path is a placeholder, which (for an entity) must
- *   always take the form of {machine_name_of_entity_type}. In the URL, the
- *   placeholder value will be the ID of an entity item. When the route is used,
- *   the entity system will load the corresponding entity item and pass it in as
- *   an object to the controller for the route.
- * - defaults: For entity form routes, use _entity_form rather than the generic
- *   _content or _form. The value is composed of the entity type machine name
- *   and a form controller type from the entity annotation (see @ref define
- *   above more more on controllers and annotation). So, in this example,
- *   block.default refers to the 'default' form controller on the block entity
- *   type, whose annotation contains:
- *   @code
- *   controllers = {
- *     "form" = {
- *       "default" = "Drupal\block\BlockForm",
- *   @endcode
- *
- * @section bundle Defining a content entity bundle
- * For entity types that use bundles, such as Node (bundles are content types)
- * and Taxonomy (bundles are vocabularies), modules and install profiles can
- * define bundles by supplying default configuration in their config/install
- * directories. (See the @link config_api Configuration API topic @endlink for
- * general information about configuration.)
- *
- * There are several good examples of this in Drupal Core:
- * - The Forum module defines a content type in node.type.forum.yml and a
- *   vocabulary in taxonomy.vocabulary.forums.yml
- * - The Book module defines a content type in node.type.book.yml
- * - The Standard install profile defines Page and Article content types in
- *   node.type.page.yml and node.type.article.yml, a Tags vocabulary in
- *   taxonomy.vocabulary.tags.yml, and a Node comment type in
- *   comment.type.comment.yml. This profile's configuration is especially
- *   instructive, because it also adds several fields to the Article type, and
- *   it sets up view and form display modes for the node types.
- *
- * @section load_query Loading, querying, and rendering entities
- * To load entities, use the entity storage manager, which is an object
- * implementing \Drupal\Core\Entity\EntityStorageInterface that you can
- * retrieve with:
- * @code
- * $storage = \Drupal::entityManager()->getStorage('your_entity_type');
- * // Or if you have a $container variable:
- * $storage = $container->get('entity.manager')->getStorage('your_entity_type');
- * @endcode
- * Here, 'your_entity_type' is the machine name of your entity type ('id'
- * annotation on the entity class), and note that you should use dependency
- * injection to retrieve this object if possible. See the
- * @link container Services and Dependency Injection topic @endlink for more
- * about how to properly retrieve services.
- *
- * To query to find entities to load, use an entity query, which is a object
- * implementing \Drupal\Core\Entity\Query\QueryInterface that you can retrieve
- * with:
- * @code
- * // Simple query:
- * $query = \Drupal::entityQuery('your_entity_type');
- * // Or, if you have a $container variable:
- * $query_service = $container->get('entity.query');
- * $query = $query_service->get('your_entity_type');
- * @endcode
- * If you need aggregation, there is an aggregate query avaialable, which
- * implements \Drupal\Core\Entity\Query\QueryAggregateInterface:
- * @code
- * $query \Drupal::entityQueryAggregate('your_entity_type');
- * // Or:
- * $query = $query_service->getAggregate('your_entity_type');
- * @endcode
- * Also, you should use dependency injection to get this object if
- * possible; the service you need is entity.query, and its methods getQuery()
- * or getAggregateQuery() will get the query object.
- *
- * In either case, you can then add conditions to your query, using methods
- * like condition(), exists(), etc. on $query; add sorting, pager, and range
- * if needed, and execute the query to return a list of entity IDs that match
- * the query.
- *
- * Here is an example, using the core File entity:
- * @code
- * $fids = Drupal::entityQuery('file')
- *   ->condition('status', FILE_STATUS_PERMANENT, '<>')
- *   ->condition('changed', REQUEST_TIME - $age, '<')
- *   ->range(0, 100)
- *   ->execute();
- * $files = $storage->loadMultiple($fids);
- * @endcode
- *
- * The normal way of viewing entities is by using a route, as described in the
- * sections above. If for some reason you need to render an entity in code in a
- * particular view mode, you can use an entity view builder, which is an object
- * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can
- * retrieve with:
- * @code
- * $view_builder = \Drupal::entityManager()->getViewBuilder('your_entity_type');
- * // Or if you have a $container variable:
- * $view_builder = $container->get('entity.manager')->getViewBuilder('your_entity_type');
- * @endcode
- * Then, to build and render the entity:
- * @code
- * // You can omit the language ID if the default language is being used.
- * $build = $view_builder->view($entity, 'view_mode_name', $language->id);
- * // $build is a render array.
- * $rendered = drupal_render($build);
- * @endcode
- *
- * @section sec_access Access checking on entities
- * Entity types define their access permission scheme in their annotation.
- * Access permissions can be quite complex, so you should not assume any
- * particular permission scheme. Instead, once you have an entity object
- * loaded, you can check for permission for a particular operation (such as
- * 'view') at the entity or field level by calling:
- * @code
- * $entity->access($operation);
- * $entity->nameOfField->access($operation);
- * @endcode
- * The interface related to access checking in entities and fields is
- * \Drupal\Core\Access\AccessibleInterface.
- *
- * The default entity access controller invokes two hooks while checking
- * access on a single entity: hook_entity_access() is invoked first, and
- * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name
- * of the entity type). If no module returns a TRUE or FALSE value from
- * either of these hooks, then the entity's default access checking takes
- * place. For create operations (creating a new entity), the hooks that
- * are invoked are hook_entity_create_access() and
- * hook_ENTITY_TYPE_create_access() instead.
- *
- * The Node entity type has a complex system for determining access, which
- * developers can interact with. This is described in the
- * @link node_access Node access topic. @endlink
- *
- * @see i18n
- * @see entity_crud
- * @}
- */
-
-/**
- * @defgroup i18n Internationalization
- * @{
- * Internationalization and translation
- *
- * The principle of internationalization is that it should be possible to make a
- * Drupal site in any language (or a multi-lingual site), where only content in
- * the desired language is displayed for any particular page request. In order
- * to make this happen, developers of modules, themes, and installation profiles
- * need to make sure that all of the displayable content and user interface (UI)
- * text that their project deals with is internationalized properly, so that it
- * can be translated using the standard Drupal translation mechanisms.
- *
- * @section internationalization Internationalization
- * Different @link info_types types of information in Drupal @endlink have
- * different methods for internationalization, and different portions of the
- * UI also have different methods for internationalization. Here is a list of
- * the different mechanisms for internationalization, and some notes:
- * - UI text is always put into code and related files in English.
- * - Any time UI text is displayed using PHP code, it should be passed through
- *   either the global t() function or a t() method on the class. If it
- *   involves plurals, it should be passed through either the global
- *   formatPlural() function or a formatPlural() method on the class. Use
- *   \Drupal\Core\StringTranslation\StringTranslationTrait to get these methods
- *   into a class.
- * - Dates displayed in the UI should be passed through the 'date' service
- *   class's format() method. Again see the Services topic; the method to
- *   call is \Drupal\Core\Datetime\Date::format().
- * - Some YML files contain UI text that is automatically translatable:
- *   - *.routing.yml files: route titles. This also applies to
- *     *.links.task.yml, *.links.action.yml, and *.links.contextual.yml files.
- *   - *.info.yml files: module names and descriptions.
- * - For configuration, make sure any configuration that is displayable to
- *   users is marked as translatable in the configuration schema. Configuration
- *   types label, text, and date_format are translatable; string is
- *   non-translatable text. See the @link config_api Config API topic @endlink
- *   for more information.
- * - For annotation, make sure that any text that is displayable in the UI
- *   is wrapped in \@Translation(). See the
- *   @link plugin_translatable Plugin translatables topic @endlink for more
- *   information.
- * - Content entities are translatable if they have
- *   @code
- *   translatable = TRUE,
- *   @endcode
- *   in their annotation. The use of entities to store user-editable content to
- *   be displayed in the site is highly recommended over creating your own
- *   method for storing, retrieving, displaying, and internationalizing content.
- * - For Twig templates, use 't' or 'trans' filters to indicate translatable
- *   text. See https://www.drupal.org/node/2133321 for more information.
- * - In JavaScript code, use the Drupal.t() and Drupal.formatPlural() functions
- *   (defined in core/misc/drupal.js) to translate UI text.
- * - If you are using a custom module, theme, etc. that is not hosted on
- *   Drupal.org, see
- *   @link interface_translation_properties Interface translation properties topic @endlink
- *   for information on how to make sure your UI text is translatable.
- *
- * @section translation Translation
- * Once your data and user interface are internationalized, the following Core
- * modules are used to translate it into different languages (machine names of
- * modules in parentheses):
- * - Language (language): Define which languages are active on the site.
- * - Interface Translation (locale): Translate UI text.
- * - Content Translation (content_translation): Translate content entities.
- * - Configuration Translation (config_translation): Translate configuration.
- *
- * The Interface Translation module deserves special mention, because besides
- * providing a UI for translating UI text, it also imports community
- * translations from the
- * @link https://localize.drupal.org Drupal translation server. @endlink If
- * UI text in Drupal Core and contributed modules, themes, and installation
- * profiles is properly internationalized (as described above), the text is
- * automatically added to the translation server for community members to
- * translate.
- *
- * @see transliteration
- * @}
- */
-
-/**
  * @defgroup cache Cache API
  * @{
  * Information about the Drupal Cache API
@@ -901,13 +561,13 @@
  * or user ID, so that site administrators can set up user accounts and roles
  * appropriately for their particular sites.
  *
- * @sec sec_define Defining permissions
+ * @section sec_define Defining permissions
  * Modules define permissions by implementing hook_permission(). The return
  * value defines machine names, human-readable names, and optionally
  * descriptions for each permission type. The machine names are the canonical
  * way to refer to permissions for access checking.
  *
- * @sec sec_access Access permission checking
+ * @section sec_access Access permission checking
  * Depending on the situation, there are several methods for ensuring that
  * access checks are done properly in Drupal:
  * - Routes: When you register a route, include a 'requirements' section that
@@ -934,7 +594,7 @@
  *   injected into the form base class as method
  *   \Drupal\Core\Form\FormBase::currentUser().
  *
- * @sec sec_entities User and role objects
+ * @section sec_entities User and role objects
  * User objects in Drupal are entity items, implementing
  * \Drupal\user\UserInterface. Role objects in Drupal are also entity items,
  * implementing \Drupal\user\RoleInterface. See the
@@ -959,79 +619,6 @@
  */
 
 /**
- * @defgroup theme_render Theme system and Render API
- * @{
- * Overview of the Theme system and Render API.
- *
- * The main purpose of Drupal's Theme system is to give themes complete control
- * over the appearance of the site, which includes the markup returned from HTTP
- * requests and the CSS files used to style that markup. In order to ensure that
- * a theme can completely customize the markup, module developers should avoid
- * directly writing HTML markup for pages, blocks, and other user-visible output
- * in their modules, and instead return structured "render arrays" (described
- * below). Doing this also increases usability, by ensuring that the markup used
- * for similar functionality on different areas of the site is the same, which
- * gives users fewer user interface patterns to learn.
- *
- * The core structure of the Render API is the render array, which is a
- * hierarchical associative array containing data to be rendered and properties
- * describing how the data should be rendered. A render array that is returned
- * by a function to specify markup to be sent to the web browser or other
- * services will eventually be rendered by a call to drupal_render(), which will
- * recurse through the render array hierarchy if appropriate, making calls into
- * the theme system to do the actual rendering. If a function or method actually
- * needs to return rendered output rather than a render array, the best practice
- * would be to create a render array, render it by calling drupal_render(), and
- * return that result, rather than writing the markup directly. See the
- * documentation of drupal_render() for more details of the rendering process.
- *
- * Each level in the hierarchy of a render array (including the outermost array)
- * has one or more array elements. Array elements whose names start with '#' are
- * known as "properties", and the array elements with other names are "children"
- * (constituting the next level of the hierarchy); the names of children are
- * flexible, while property names are specific to the Render API and the
- * particular type of data being rendered. A special case of render arrays is a
- * form array, which specifies the form elements for an HTML form; see the
- * @link form_api Form generation topic @endlink for more information on forms.
- *
- * Render arrays (at each level in the hierarchy) will usually have one of the
- * following three properties defined:
- * - #type: Specifies that the array contains data and options for a particular
- *   type of "render element" (examples: 'form', for an HTML form; 'textfield',
- *   'submit', and other HTML form element types; 'table', for a table with
- *   rows, columns, and headers). Modules define render elements by implementing
- *   hook_element_info(), which specifies the properties that are used in render
- *   arrays to provide the data and options, and default values for these
- *   properties. Look through implementations of hook_element_info() to discover
- *   what render elements are available.
- * - #theme: Specifies that the array contains data to be themed by a particular
- *   theme hook. Modules define theme hooks by implementing hook_theme(), which
- *   specifies the input "variables" used to provide data and options; if a
- *   hook_theme() implementation specifies variable 'foo', then in a render
- *   array, you would provide this data using property '#foo'. Modules
- *   implementing hook_theme() also need to provide a default implementation for
- *   each of their theme hooks, normally in a Twig file. For more information
- *   and to discover available theme hooks, see the documentation of
- *   hook_theme() and the
- *   @link themeable Default theme implementations topic. @endlink
- * - #markup: Specifies that the array provides HTML markup directly. Unless the
- *   markup is very simple, such as an explanation in a paragraph tag, it is
- *   normally preferable to use #theme or #type instead, so that the theme can
- *   customize the markup.
- *
- * For further information on the Theme and Render APIs, see:
- * - https://drupal.org/documentation/theme
- * - https://drupal.org/developing/modules/8
- * - https://drupal.org/node/722174
- * - https://drupal.org/node/933976
- * - https://drupal.org/node/930760
- *
- * @todo Check these links. Some are for Drupal 7, and might need updates for
- *   Drupal 8.
- * @}
- */
-
-/**
  * @defgroup container Services and Dependency Injection Container
  * @{
  * Overview of the Dependency Injection Container and Services.
@@ -1463,7 +1050,7 @@
  * \Drupal\system\Plugin\Derivative\SystemMenuBlock (derivative class) are a
  * good example to look at.
  *
- * @sec sec_use Performing tasks involving plugins
+ * @section sec_use Performing tasks involving plugins
  * Here are the steps to follow to perform a task that involves plugins:
  * - Locate the machine name of the plugin manager service, and instantiate the
  *   service. See the @link container Services topic @endlink for more
@@ -1562,6 +1149,265 @@
  */
 
 /**
+ * @defgroup hooks Hooks
+ * @{
+ * Define functions that alter the behavior of Drupal core.
+ *
+ * One way for modules to alter the core behavior of Drupal (or another module)
+ * is to use hooks. Hooks are specially-named functions that a module defines
+ * (this is known as "implementing the hook"), which are discovered and called
+ * at specific times to alter or add to the base behavior or data (this is
+ * known as "invoking the hook"). Each hook has a name (example:
+ * hook_batch_alter()), a defined set of parameters, and a defined return value.
+ * Your modules can implement hooks that are defined by Drupal core or other
+ * modules that they interact with. Your modules can also define their own
+ * hooks, in order to let other modules interact with them.
+ *
+ * To implement a hook:
+ * - Locate the documentation for the hook. Hooks are documented in *.api.php
+ *   files, by defining functions whose name starts with "hook_" (these
+ *   files and their functions are never loaded by Drupal -- they exist solely
+ *   for documentation). The function should have a documentation header, as
+ *   well as a sample function body. For example, in the core file
+ *   system.api.php, you can find hooks such as hook_batch_alter(). Also, if
+ *   you are viewing this documentation on an API reference site, the Core
+ *   hooks will be listed in this topic.
+ * - Copy the function to your module's .module file.
+ * - Change the name of the function, substituting your module's short name
+ *   (name of the module's directory, and .info.yml file without the extension)
+ *   for the "hook" part of the sample function name. For instance, to implemnt
+ *   hook_batch_alter(), you would rename it to my_module_batch_alter().
+ * - Edit the documentation for the function (normally, your implementation
+ *   should just have one line saying "Implements hook_batch_alter().").
+ * - Edit the body of the function, substituting in what you need your module
+ *   to do.
+ *
+ * To define a hook:
+ * - Choose a unique name for your hook. It should start with "hook_", followed
+ *   by your module's short name.
+ * - Provide documentation in a *.api.php file in your module's main
+ *   directory. See the "implementing" section above for details of what this
+ *   should contain (parameters, return value, and sample function body).
+ * - Invoke the hook in your module's code.
+ *
+ * To invoke a hook, use methods on
+ * \Drupal\Core\Extension\ModuleHandlerInterface such as alter(), invoke(),
+ * and invokeAll(). You can obtain a module handler by calling
+ * \Drupal::moduleHandler(), or getting the 'module_handler' service on an
+ * injected container.
+ *
+ * @see extending
+ * @see themeable
+ * @see callbacks
+ * @see \Drupal\Core\Extension\ModuleHandlerInterface
+ * @see \Drupal::moduleHandler()
+ *
+ * @}
+ */
+
+/**
+ * @defgroup callbacks Callbacks
+ * @{
+ * Callback function signatures.
+ *
+ * Drupal's API sometimes uses callback functions to allow you to define how
+ * some type of processing happens. A callback is a function with a defined
+ * signature, which you define in a module. Then you pass the function name as
+ * a parameter to a Drupal API function or return it as part of a hook
+ * implementation return value, and your function is called at an appropriate
+ * time. For instance, when setting up batch processing you might need to
+ * provide a callback function for each processing step and/or a callback for
+ * when processing is finished; you would do that by defining these functions
+ * and passing their names into the batch setup function.
+ *
+ * Callback function signatures, like hook definitions, are described by
+ * creating and documenting dummy functions in a *.api.php file; normally, the
+ * dummy callback function's name should start with "callback_", and you should
+ * document the parameters and return value and provide a sample function body.
+ * Then your API documentation can refer to this callback function in its
+ * documentation. A user of your API can usually name their callback function
+ * anything they want, although a standard name would be to replace "callback_"
+ * with the module name.
+ *
+ * @see hooks
+ * @see themeable
+ *
+ * @}
+ */
+
+/**
+ * @defgroup form_api Form generation
+ * @{
+ * Describes how to generate and manipulate forms and process form submissions.
+ *
+ * Drupal provides a Form API in order to achieve consistency in its form
+ * processing and presentation, while simplifying code and reducing the amount
+ * of HTML that must be explicitly generated by a module.
+ *
+ * @section generating_forms Creating forms
+ * Forms are defined as classes that implement the
+ * \Drupal\Core\Form\FormInterface and are built using the
+ * \Drupal\Core\Form\FormBuilder class. Drupal provides a couple of utility
+ * classes that can be extended as a starting point for most basic forms, the
+ * most commonly used of which is \Drupal\Core\Form\FormBase. FormBuilder
+ * handles the low level processing of forms such as rendering the necessary
+ * HTML, initial processing of incoming $_POST data, and delegating to your
+ * implementation of FormInterface for validation and processing of submitted
+ * data.
+ *
+ * Here is an example of a Form class:
+ * @code
+ * namespace Drupal\mymodule\Form;
+ *
+ * use Drupal\Core\Form\FormBase;
+ *
+ * class ExampleForm extends FormBase {
+ *   public function getFormId() {
+ *     // Unique ID of the form.
+ *     return 'example_form';
+ *   }
+ *
+ *   public function buildForm(array $form, FormStateInterface $form_state) {
+ *     // Create a $form API array.
+ *     $form['phone_number'] = array(
+ *       '#type' => 'tel',
+ *       '#title' => $this->t('Your phone number')
+ *     );
+ *     return $form;
+ *   }
+ *
+ *   public function validateForm(array &$form, FormStateInterface $form_state) {
+ *     // Validate submitted form data.
+ *   }
+ *
+ *   public function submitForm(array &$form, FormStateInterface $form_state) {
+ *     // Handle submitted form data.
+ *   }
+ * }
+ * @endcode
+ *
+ * @section retrieving_forms Retrieving and displaying forms
+ * \Drupal::formBuilder()->getForm() should be used to handle retrieving,
+ * processing, and displaying a rendered HTML form. Given the ExampleForm
+ * defined above,
+ * \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\ExampleForm') would
+ * return the rendered HTML of the form defined by ExampleForm::buildForm(), or
+ * call the validateForm() and submitForm(), methods depending on the current
+ * processing state.
+ *
+ * The argument to \Drupal::formBuilder()->getForm() is the name of a class that
+ * implements FormBuilderInterface. Any additional arguments passed to the
+ * getForm() method will be passed along as additional arguments to the
+ * ExampleForm::buildForm() method.
+ *
+ * For example:
+ * @code
+ * $extra = '612-123-4567';
+ * $form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\ExampleForm', $extra);
+ * ...
+ * public function buildForm(array $form, FormStateInterface $form_state, $extra = NULL)
+ *   $form['phone_number'] = array(
+ *     '#type' => 'tel',
+ *     '#title' => $this->t('Your phone number'),
+ *     '#value' => $extra,
+ *   );
+ *   return $form;
+ * }
+ * @endcode
+ *
+ * Alternatively, forms can be built directly via the routing system which will
+ * take care of calling \Drupal::formBuilder()->getForm(). The following example
+ * demonstrates the use of a routing.yml file to display a form at the the
+ * given route.
+ *
+ * @code
+ * example.form:
+ *   path: '/example-form'
+ *   defaults:
+ *     _title: 'Example form'
+ *     _form: '\Drupal\mymodule\Form\ExampleForm'
+ * @endcode
+ *
+ * The $form argument to form-related functions is a structured array containing
+ * the elements and properties of the form. For information on the array
+ * components and format, and more detailed explanations of the Form API
+ * workflow, see the
+ * @link forms_api_reference.html Form API reference @endlink
+ * and the
+ * @link https://drupal.org/node/2117411 Form API documentation section. @endlink
+ * In addition, there is a set of Form API tutorials in
+ * @link form_example_tutorial.inc the Form Example Tutorial @endlink which
+ * provide basics all the way up through multistep forms.
+ *
+ * In the form builder, validation, submission, and other form methods,
+ * $form_state is the primary influence on the processing of the form and is
+ * passed by reference to most methods, so they can use it to communicate with
+ * the form system and each other.
+ *
+ * See \Drupal\Core\Form\FormBuilder::buildForm() for documentation of
+ * $form_state keys.
+ */
+
+/**
+ * @} End of "defgroup form_api".
+ */
+
+/**
+ * @defgroup queue Queue operations
+ * @{
+ * Queue items to allow later processing.
+ *
+ * The queue system allows placing items in a queue and processing them later.
+ * The system tries to ensure that only one consumer can process an item.
+ *
+ * Before a queue can be used it needs to be created by
+ * Drupal\Core\Queue\QueueInterface::createQueue().
+ *
+ * Items can be added to the queue by passing an arbitrary data object to
+ * Drupal\Core\Queue\QueueInterface::createItem().
+ *
+ * To process an item, call Drupal\Core\Queue\QueueInterface::claimItem() and
+ * specify how long you want to have a lease for working on that item.
+ * When finished processing, the item needs to be deleted by calling
+ * Drupal\Core\Queue\QueueInterface::deleteItem(). If the consumer dies, the
+ * item will be made available again by the Drupal\Core\Queue\QueueInterface
+ * implementation once the lease expires. Another consumer will then be able to
+ * receive it when calling Drupal\Core\Queue\QueueInterface::claimItem().
+ * Due to this, the processing code should be aware that an item might be handed
+ * over for processing more than once.
+ *
+ * The $item object used by the Drupal\Core\Queue\QueueInterface can contain
+ * arbitrary metadata depending on the implementation. Systems using the
+ * interface should only rely on the data property which will contain the
+ * information passed to Drupal\Core\Queue\QueueInterface::createItem().
+ * The full queue item returned by Drupal\Core\Queue\QueueInterface::claimItem()
+ * needs to be passed to Drupal\Core\Queue\QueueInterface::deleteItem() once
+ * processing is completed.
+ *
+ * There are two kinds of queue backends available: reliable, which preserves
+ * the order of messages and guarantees that every item will be executed at
+ * least once. The non-reliable kind only does a best effort to preserve order
+ * in messages and to execute them at least once but there is a small chance
+ * that some items get lost. For example, some distributed back-ends like
+ * Amazon SQS will be managing jobs for a large set of producers and consumers
+ * where a strict FIFO ordering will likely not be preserved. Another example
+ * would be an in-memory queue backend which might lose items if it crashes.
+ * However, such a backend would be able to deal with significantly more writes
+ * than a reliable queue and for many tasks this is more important. See
+ * aggregator_cron() for an example of how to effectively utilize a
+ * non-reliable queue. Another example is doing Twitter statistics -- the small
+ * possibility of losing a few items is insignificant next to power of the
+ * queue being able to keep up with writes. As described in the processing
+ * section, regardless of the queue being reliable or not, the processing code
+ * should be aware that an item might be handed over for processing more than
+ * once (because the processing code might time out before it finishes).
+ */
+
+/**
+ * @} End of "defgroup queue".
+ */
+
+/**
  * @addtogroup hooks
  * @{
  */
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index f835aa9..41d8217 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -236,6 +236,267 @@
  */
 
 /**
+ * @defgroup entity_api Entity API
+ * @{
+ * Describes how to define and manipulate content and configuration entities.
+ *
+ * Entities, in Drupal, are objects that are used for persistent storage of
+ * content and configuration information. See the
+ * @link info_types Information types topic @endlink for an overview of the
+ * different types of information, and the
+ * @link config_api Configuration API topic @endlink for more about the
+ * configuration API.
+ *
+ * Each entity is an instance of a particular "entity type". Some content entity
+ * types have sub-types, which are known as "bundles", while for other entity
+ * types, there is only a single bundle. For example, the Node content entity
+ * type, which is used for the main content pages in Drupal, has bundles that
+ * are known as "content types", while the User content type, which is used for
+ * user accounts, has only one bundle.
+ *
+ * The sections below have more information about entities and the Entity API;
+ * for more detailed information, see https://drupal.org/developing/api/entity
+ *
+ * @section define Defining an entity type
+ * Entity types are defined by modules, using Drupal's Plugin API (see the
+ * @link plugin_api Plugin API topic @endlink for more information about plugins
+ * in general). Here are the steps to follow to define a new entity type:
+ * - Choose a unique machine name, or ID, for your entity type. This normally
+ *   starts with (or is the same as) your module's machine name. It should be
+ *   as short as possible, and may not exceed 32 characters.
+ * - Define an interface for your entity's get/set methods, extending either
+ *   \Drupal\Core\Config\Entity\ConfigEntityInterface or
+ *   \Drupal\Core\Entity\ContentEntityInterface.
+ * - Define a class for your entity, implementing your interface and extending
+ *   either \Drupal\Core\Config\Entity\ConfigEntityBase or
+ *   \Drupal\Core\Entity\ContentEntityBase, with annotation for
+ *   \@ConfigEntityType or \@ContentEntityType in its documentation block.
+ * - The 'id' annotation gives the entity type ID, and the 'label' annotation
+ *   gives the human-readable name of the entity type. If you are defining a
+ *   content entity type that uses bundles, the 'bundle_label' annotation gives
+ *   the human-readable name to use for a bundle of this entity type (for
+ *   example, "Content type" for the Node entity).
+ * - The annotation will refer to several controller classes, which you will
+ *   also need to define:
+ *   - list_builder: Define a class that extends
+ *     \Drupal\Core\Config\Entity\ConfigEntityListBuilder (for configuration
+ *     entities) or \Drupal\Core\Entity\EntityListBuilder (for content
+ *     entities), to provide an administrative overview for your entities.
+ *   - add and edit forms, or default form: Define a class (or two) that
+ *     extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms
+ *     for your entities. For content entities, base class
+ *     \Drupal\Core\Entity\ContentEntityForm is a better starting point.
+ *   - delete form: Define a class that extends
+ *     \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete
+ *     confirmation form for your entities.
+ *   - view_builder: For content entities and config entities that need to be
+ *     viewed, define a class that implements
+ *     \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending
+ *     \Drupal\Core\Entity\EntityViewBuilder), to display a single entity.
+ *   - translation: For translatable content entities (if the 'translatable'
+ *     annotation has value TRUE), define a class that extends
+ *     \Drupal\content_translation\ContentTranslationHandler, to translate
+ *     the content. Configuration translation is handled automatically by the
+ *     Configuration Translation module, without the need of a controller class.
+ *   - access: If your configuration entity has complex permissions, you might
+ *     need an access controller, implementing
+ *     \Drupal\Core\Entity\EntityAccessControllerInterface, but most entities
+ *     can just use the 'admin_permission' annotation instead. Note that if you
+ *     are creating your own access controller, you should override the
+ *     checkAccess() and checkCreateAccess() methods, not access().
+ *   - storage: A class implementing
+ *     \Drupal\Core\Entity\EntityStorageInterface. If not specified, content
+ *     entities will use \Drupal\Core\Entity\ContentEntityDatabaseStorage, and
+ *     config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
+ *     You can extend one of these classes to provide custom behavior.
+ * - For content entities, the annotation will refer to a number of database
+ *   tables and their fields. These annotation properties, such as 'base_table',
+ *   'data_table', 'entity_keys', etc., are documented on
+ *   \Drupal\Core\Entity\EntityType. Your module will also need to set up its
+ *   database tables using hook_schema().
+ * - For content entities that are displayed on their own pages, the annotation
+ *   will refer to a 'uri_callback' function, which takes an object of the
+ *   entity interface you have defined as its parameter, and returns routing
+ *   information for the entity page; see node_uri() for an example. You will
+ *   also need to add a corresponding route to your module's routing.yml file;
+ *   see the node.view route in node.routing.yml for an example, and see
+ *   @ref sec_routes below for some notes.
+ * - Define routing and links for the various URLs associated with the entity.
+ *   These go into the 'links' annotation, with the link type as the key, and
+ *   the route machine name (defined in your module's routing.yml file) as the
+ *   value; see @ref sec_routes below for some routing notes. Typical link
+ *   types are:
+ *   - canonical: Default link, either to view (if entities are viewed on their
+ *     own pages) or edit the entity.
+ *   - delete-form: Confirmation form to delete the entity.
+ *   - edit-form: Editing form.
+ *   - admin-form: Form for editing bundle or entity type settings.
+ *   - Other link types specific to your entity type can also be defined.
+ * - If your content entity has bundles, you will also need to define a second
+ *   plugin to handle the bundles. This plugin is itself a configuration entity
+ *   type, so follow the steps here to define it. The machine name ('id'
+ *   annotation) of this configuration entity class goes into the
+ *   'bundle_entity_type' annotation on the entity type class. For example, for
+ *   the Node entity, the bundle class is \Drupal\node\Entity\NodeType, whose
+ *   machine name is 'node_type'. This is the annotation value for
+ *   'bundle_entity_type' on the \Drupal\node\Entity\Node class. Also, the
+ *   bundle config entity type annotation must have a 'bundle_of' entry,
+ *   giving the machine name of the entity type it is acting as a bundle for.
+ * - Additional annotations can be seen on entity class examples such as
+ *   \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
+ *   (configuration). These annotations are documented on
+ *   \Drupal\Core\Entity\EntityType.
+ *
+ * @section sec_routes Entity routes
+ * Entity routes, like other routes, are defined in *.routing.yml files; see
+ * the @link menu Menu and routing @endlink topic for more information. Here
+ * is a typical entry, for the block configure form:
+ * @code
+ * block.admin_edit:
+ *   path: '/admin/structure/block/manage/{block}'
+ *   defaults:
+ *     _entity_form: 'block.default'
+ *     _title: 'Configure block'
+ *   requirements:
+ *     _entity_access: 'block.update'
+ * @endcode
+ * Some notes:
+ * - path: The {block} in the path is a placeholder, which (for an entity) must
+ *   always take the form of {machine_name_of_entity_type}. In the URL, the
+ *   placeholder value will be the ID of an entity item. When the route is used,
+ *   the entity system will load the corresponding entity item and pass it in as
+ *   an object to the controller for the route.
+ * - defaults: For entity form routes, use _entity_form rather than the generic
+ *   _content or _form. The value is composed of the entity type machine name
+ *   and a form controller type from the entity annotation (see @ref define
+ *   above more more on controllers and annotation). So, in this example,
+ *   block.default refers to the 'default' form controller on the block entity
+ *   type, whose annotation contains:
+ *   @code
+ *   controllers = {
+ *     "form" = {
+ *       "default" = "Drupal\block\BlockForm",
+ *   @endcode
+ *
+ * @section bundle Defining a content entity bundle
+ * For entity types that use bundles, such as Node (bundles are content types)
+ * and Taxonomy (bundles are vocabularies), modules and install profiles can
+ * define bundles by supplying default configuration in their config/install
+ * directories. (See the @link config_api Configuration API topic @endlink for
+ * general information about configuration.)
+ *
+ * There are several good examples of this in Drupal Core:
+ * - The Forum module defines a content type in node.type.forum.yml and a
+ *   vocabulary in taxonomy.vocabulary.forums.yml
+ * - The Book module defines a content type in node.type.book.yml
+ * - The Standard install profile defines Page and Article content types in
+ *   node.type.page.yml and node.type.article.yml, a Tags vocabulary in
+ *   taxonomy.vocabulary.tags.yml, and a Node comment type in
+ *   comment.type.comment.yml. This profile's configuration is especially
+ *   instructive, because it also adds several fields to the Article type, and
+ *   it sets up view and form display modes for the node types.
+ *
+ * @section load_query Loading, querying, and rendering entities
+ * To load entities, use the entity storage manager, which is an object
+ * implementing \Drupal\Core\Entity\EntityStorageInterface that you can
+ * retrieve with:
+ * @code
+ * $storage = \Drupal::entityManager()->getStorage('your_entity_type');
+ * // Or if you have a $container variable:
+ * $storage = $container->get('entity.manager')->getStorage('your_entity_type');
+ * @endcode
+ * Here, 'your_entity_type' is the machine name of your entity type ('id'
+ * annotation on the entity class), and note that you should use dependency
+ * injection to retrieve this object if possible. See the
+ * @link container Services and Dependency Injection topic @endlink for more
+ * about how to properly retrieve services.
+ *
+ * To query to find entities to load, use an entity query, which is a object
+ * implementing \Drupal\Core\Entity\Query\QueryInterface that you can retrieve
+ * with:
+ * @code
+ * // Simple query:
+ * $query = \Drupal::entityQuery('your_entity_type');
+ * // Or, if you have a $container variable:
+ * $query_service = $container->get('entity.query');
+ * $query = $query_service->get('your_entity_type');
+ * @endcode
+ * If you need aggregation, there is an aggregate query avaialable, which
+ * implements \Drupal\Core\Entity\Query\QueryAggregateInterface:
+ * @code
+ * $query \Drupal::entityQueryAggregate('your_entity_type');
+ * // Or:
+ * $query = $query_service->getAggregate('your_entity_type');
+ * @endcode
+ * Also, you should use dependency injection to get this object if
+ * possible; the service you need is entity.query, and its methods getQuery()
+ * or getAggregateQuery() will get the query object.
+ *
+ * In either case, you can then add conditions to your query, using methods
+ * like condition(), exists(), etc. on $query; add sorting, pager, and range
+ * if needed, and execute the query to return a list of entity IDs that match
+ * the query.
+ *
+ * Here is an example, using the core File entity:
+ * @code
+ * $fids = Drupal::entityQuery('file')
+ *   ->condition('status', FILE_STATUS_PERMANENT, '<>')
+ *   ->condition('changed', REQUEST_TIME - $age, '<')
+ *   ->range(0, 100)
+ *   ->execute();
+ * $files = $storage->loadMultiple($fids);
+ * @endcode
+ *
+ * The normal way of viewing entities is by using a route, as described in the
+ * sections above. If for some reason you need to render an entity in code in a
+ * particular view mode, you can use an entity view builder, which is an object
+ * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can
+ * retrieve with:
+ * @code
+ * $view_builder = \Drupal::entityManager()->getViewBuilder('your_entity_type');
+ * // Or if you have a $container variable:
+ * $view_builder = $container->get('entity.manager')->getViewBuilder('your_entity_type');
+ * @endcode
+ * Then, to build and render the entity:
+ * @code
+ * // You can omit the language ID if the default language is being used.
+ * $build = $view_builder->view($entity, 'view_mode_name', $language->id);
+ * // $build is a render array.
+ * $rendered = drupal_render($build);
+ * @endcode
+ *
+ * @section sec_access Access checking on entities
+ * Entity types define their access permission scheme in their annotation.
+ * Access permissions can be quite complex, so you should not assume any
+ * particular permission scheme. Instead, once you have an entity object
+ * loaded, you can check for permission for a particular operation (such as
+ * 'view') at the entity or field level by calling:
+ * @code
+ * $entity->access($operation);
+ * $entity->nameOfField->access($operation);
+ * @endcode
+ * The interface related to access checking in entities and fields is
+ * \Drupal\Core\Access\AccessibleInterface.
+ *
+ * The default entity access controller invokes two hooks while checking
+ * access on a single entity: hook_entity_access() is invoked first, and
+ * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name
+ * of the entity type). If no module returns a TRUE or FALSE value from
+ * either of these hooks, then the entity's default access checking takes
+ * place. For create operations (creating a new entity), the hooks that
+ * are invoked are hook_entity_create_access() and
+ * hook_ENTITY_TYPE_create_access() instead.
+ *
+ * The Node entity type has a complex system for determining access, which
+ * developers can interact with. This is described in the
+ * @link node_access Node access topic. @endlink
+ *
+ * @see i18n
+ * @see entity_crud
+ * @}
+ */
+
+/**
  * @addtogroup hooks
  * @{
  */
@@ -1278,15 +1539,15 @@ function hook_entity_display_build_alter(&$build, $context) {
  *   The entity that is about to be shown on the form.
  * @param $operation
  *   The current operation.
- * @param array $form_state
- *   An associative array containing the current state of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
  * @see hook_ENTITY_TYPE_prepare_form()
  *
  * @ingroup entity_crud
  */
-function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, array &$form_state) {
+function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
   if ($operation == 'edit') {
     $entity->label->value = 'Altered label';
     $form_state['mymodule']['label_altered'] = TRUE;
@@ -1304,15 +1565,15 @@ function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $
  *   The entity that is about to be shown on the form.
  * @param $operation
  *   The current operation.
- * @param array $form_state
- *   An associative array containing the current state of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
  *
  * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
  * @see hook_entity_prepare_form()
  *
  * @ingroup entity_crud
  */
-function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, array &$form_state) {
+function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
   if ($operation == 'edit') {
     $entity->label->value = 'Altered label';
     $form_state['mymodule']['label_altered'] = TRUE;
diff --git a/core/modules/system/language.api.php b/core/modules/system/language.api.php
index 1fb40e2..3a74f82 100644
--- a/core/modules/system/language.api.php
+++ b/core/modules/system/language.api.php
@@ -8,6 +8,85 @@
 use Drupal\Core\Language\LanguageInterface;
 
 /**
+ * @defgroup i18n Internationalization
+ * @{
+ * Internationalization and translation
+ *
+ * The principle of internationalization is that it should be possible to make a
+ * Drupal site in any language (or a multi-lingual site), where only content in
+ * the desired language is displayed for any particular page request. In order
+ * to make this happen, developers of modules, themes, and installation profiles
+ * need to make sure that all of the displayable content and user interface (UI)
+ * text that their project deals with is internationalized properly, so that it
+ * can be translated using the standard Drupal translation mechanisms.
+ *
+ * @section internationalization Internationalization
+ * Different @link info_types types of information in Drupal @endlink have
+ * different methods for internationalization, and different portions of the
+ * UI also have different methods for internationalization. Here is a list of
+ * the different mechanisms for internationalization, and some notes:
+ * - UI text is always put into code and related files in English.
+ * - Any time UI text is displayed using PHP code, it should be passed through
+ *   either the global t() function or a t() method on the class. If it
+ *   involves plurals, it should be passed through either the global
+ *   formatPlural() function or a formatPlural() method on the class. Use
+ *   \Drupal\Core\StringTranslation\StringTranslationTrait to get these methods
+ *   into a class.
+ * - Dates displayed in the UI should be passed through the 'date' service
+ *   class's format() method. Again see the Services topic; the method to
+ *   call is \Drupal\Core\Datetime\Date::format().
+ * - Some YML files contain UI text that is automatically translatable:
+ *   - *.routing.yml files: route titles. This also applies to
+ *     *.links.task.yml, *.links.action.yml, and *.links.contextual.yml files.
+ *   - *.info.yml files: module names and descriptions.
+ * - For configuration, make sure any configuration that is displayable to
+ *   users is marked as translatable in the configuration schema. Configuration
+ *   types label, text, and date_format are translatable; string is
+ *   non-translatable text. See the @link config_api Config API topic @endlink
+ *   for more information.
+ * - For annotation, make sure that any text that is displayable in the UI
+ *   is wrapped in \@Translation(). See the
+ *   @link plugin_translatable Plugin translatables topic @endlink for more
+ *   information.
+ * - Content entities are translatable if they have
+ *   @code
+ *   translatable = TRUE,
+ *   @endcode
+ *   in their annotation. The use of entities to store user-editable content to
+ *   be displayed in the site is highly recommended over creating your own
+ *   method for storing, retrieving, displaying, and internationalizing content.
+ * - For Twig templates, use 't' or 'trans' filters to indicate translatable
+ *   text. See https://www.drupal.org/node/2133321 for more information.
+ * - In JavaScript code, use the Drupal.t() and Drupal.formatPlural() functions
+ *   (defined in core/misc/drupal.js) to translate UI text.
+ * - If you are using a custom module, theme, etc. that is not hosted on
+ *   Drupal.org, see
+ *   @link interface_translation_properties Interface translation properties topic @endlink
+ *   for information on how to make sure your UI text is translatable.
+ *
+ * @section translation Translation
+ * Once your data and user interface are internationalized, the following Core
+ * modules are used to translate it into different languages (machine names of
+ * modules in parentheses):
+ * - Language (language): Define which languages are active on the site.
+ * - Interface Translation (locale): Translate UI text.
+ * - Content Translation (content_translation): Translate content entities.
+ * - Configuration Translation (config_translation): Translate configuration.
+ *
+ * The Interface Translation module deserves special mention, because besides
+ * providing a UI for translating UI text, it also imports community
+ * translations from the
+ * @link https://localize.drupal.org Drupal translation server. @endlink If
+ * UI text in Drupal Core and contributed modules, themes, and installation
+ * profiles is properly internationalized (as described above), the text is
+ * automatically added to the translation server for community members to
+ * translate.
+ *
+ * @see transliteration
+ * @}
+ */
+
+/**
  * @addtogroup hooks
  * @{
  */
diff --git a/core/modules/system/src/Controller/AdminController.php b/core/modules/system/src/Controller/AdminController.php
index 7445d52..d9800f0 100644
--- a/core/modules/system/src/Controller/AdminController.php
+++ b/core/modules/system/src/Controller/AdminController.php
@@ -36,7 +36,7 @@ public function index() {
         // Sort links by title.
         uasort($admin_tasks, array('\Drupal\Component\Utility\SortArray', 'sortByTitleElement'));
         // Move 'Configure permissions' links to the bottom of each section.
-        $permission_key = "user.admin.people.permissions.$module";
+        $permission_key = "user.admin_permissions.$module";
         if (isset($admin_tasks[$permission_key])) {
           $permission_task = $admin_tasks[$permission_key];
           unset($admin_tasks[$permission_key]);
diff --git a/core/modules/system/src/Controller/FormAjaxController.php b/core/modules/system/src/Controller/FormAjaxController.php
index bc43c49..be4c98d 100644
--- a/core/modules/system/src/Controller/FormAjaxController.php
+++ b/core/modules/system/src/Controller/FormAjaxController.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Controller;
 
+use Drupal\Core\Form\FormState;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -70,7 +71,7 @@ public function content(Request $request) {
    * @throws Symfony\Component\HttpKernel\Exception\HttpExceptionInterface
    */
   protected function getForm(Request $request) {
-    $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $form_state = new FormState();
     $form_build_id = $request->request->get('form_build_id');
 
     // Get the form from the cache.
diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php
index b960968..c811e85 100644
--- a/core/modules/system/src/Controller/SystemController.php
+++ b/core/modules/system/src/Controller/SystemController.php
@@ -12,6 +12,8 @@
 use Drupal\Core\Entity\Query\QueryFactory;
 use Drupal\Core\Extension\ThemeHandlerInterface;
 use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Menu\MenuLinkTreeInterface;
+use Drupal\Core\Menu\MenuTreeParameters;
 use Drupal\Core\Theme\ThemeAccessCheck;
 use Drupal\system\SystemManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -57,6 +59,13 @@ class SystemController extends ControllerBase {
   protected $themeHandler;
 
   /**
+   * The menu link tree service.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
+   */
+  protected $menuLinkTree;
+
+  /**
    * Constructs a new SystemController.
    *
    * @param \Drupal\system\SystemManager $systemManager
@@ -69,13 +78,16 @@ class SystemController extends ControllerBase {
    *   The form builder.
    * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
    *   The theme handler.
+   * @param \Drupal\Core\Menu\MenuLinkTreeInterface
+   *   The menu link tree service.
    */
-  public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler) {
+  public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler, MenuLinkTreeInterface $menu_link_tree) {
     $this->systemManager = $systemManager;
     $this->queryFactory = $queryFactory;
     $this->themeAccess = $theme_access;
     $this->formBuilder = $form_builder;
     $this->themeHandler = $theme_handler;
+    $this->menuLinkTree = $menu_link_tree;
   }
 
   /**
@@ -87,66 +99,49 @@ public static function create(ContainerInterface $container) {
       $container->get('entity.query'),
       $container->get('access_check.theme'),
       $container->get('form_builder'),
-      $container->get('theme_handler')
+      $container->get('theme_handler'),
+      $container->get('menu.link_tree')
     );
   }
 
   /**
    * Provide the administration overview page.
    *
-   * @param string $path
-   *   The administrative path for which to display child links.
+   * @param string $link_id
+   *   The ID of the administrative path link for which to display child links.
    *
    * @return array
    *   A renderable array of the administration overview page.
    */
-  public function overview($path) {
+  public function overview($link_id) {
     // Check for status report errors.
     if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
       drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))), 'error');
     }
+    // Load all menu links below it.
+    $parameters = new MenuTreeParameters();
+    $parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
+    $tree = $this->menuLinkTree->load(NULL, $parameters);
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+      array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    );
+    $tree = $this->menuLinkTree->transform($tree, $manipulators);
     $blocks = array();
-    // Load all links on $path and menu links below it.
-    $query = $this->queryFactory->get('menu_link')
-      ->condition('link_path', $path)
-      ->condition('module', 'system');
-    $result = $query->execute();
-    $menu_link_storage = $this->entityManager()->getStorage('menu_link');
-    if ($system_link = $menu_link_storage->loadMultiple($result)) {
-      $system_link = reset($system_link);
-      $query = $this->queryFactory->get('menu_link')
-        ->condition('link_path', 'admin/help', '<>')
-        ->condition('menu_name', $system_link->menu_name)
-        ->condition('plid', $system_link->id())
-        ->condition('hidden', 0);
-      $result = $query->execute();
-      if (!empty($result)) {
-        $menu_links = $menu_link_storage->loadMultiple($result);
-        foreach ($menu_links as $item) {
-          _menu_link_translate($item);
-          if (!$item['access']) {
-            continue;
-          }
-          // The link description, either derived from 'description' in hook_menu()
-          // or customized via Menu UI module is used as title attribute.
-          if (!empty($item['localized_options']['attributes']['title'])) {
-            $item['description'] = $item['localized_options']['attributes']['title'];
-            unset($item['localized_options']['attributes']['title']);
-          }
-          $block = $item;
-          $block['content'] = array(
-            '#theme' => 'admin_block_content',
-            '#content' => $this->systemManager->getAdminBlock($item),
-          );
+    foreach ($tree as $key => $element) {
+      $link = $element->link;
+      $block['title'] = $link->getTitle();
+      $block['description'] = $link->getDescription();
+      $block['content'] = array(
+        '#theme' => 'admin_block_content',
+        '#content' => $this->systemManager->getAdminBlock($link),
+      );
 
-          if (!empty($block['content']['#content'])) {
-            // Prepare for sorting as in function _menu_tree_check_access().
-            // The weight is offset so it is always positive, with a uniform 5-digits.
-            $blocks[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $block;
-          }
-        }
+      if (!empty($block['content']['#content'])) {
+        $blocks[$key] = $block;
       }
     }
+
     if ($blocks) {
       ksort($blocks);
       return array(
diff --git a/core/modules/system/src/Form/CronForm.php b/core/modules/system/src/Form/CronForm.php
index b7e4423..1ae69a1 100644
--- a/core/modules/system/src/Form/CronForm.php
+++ b/core/modules/system/src/Form/CronForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\CronInterface;
 use Drupal\Core\Datetime\Date as DateFormatter;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -82,7 +83,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.cron');
 
     $form['description'] = array(
@@ -123,7 +124,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.cron')
       ->set('threshold.autorun', $form_state['values']['cron_safe_threshold'])
       ->save();
@@ -134,7 +135,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Runs cron and reloads the page.
    */
-  public function submitCron(array &$form, array &$form_state) {
+  public function submitCron(array &$form, FormStateInterface $form_state) {
     // Run cron manually from Cron form.
     if ($this->cron->run()) {
       drupal_set_message(t('Cron run successfully.'));
diff --git a/core/modules/system/src/Form/DateFormatAddForm.php b/core/modules/system/src/Form/DateFormatAddForm.php
index b9289a2..22333e7 100644
--- a/core/modules/system/src/Form/DateFormatAddForm.php
+++ b/core/modules/system/src/Form/DateFormatAddForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\system\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a form for adding a date format.
  */
@@ -15,7 +17,7 @@ class DateFormatAddForm extends DateFormatFormBase {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = t('Add format');
     return $actions;
@@ -24,7 +26,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
     drupal_set_message(t('Custom date format added.'));
   }
diff --git a/core/modules/system/src/Form/DateFormatDeleteForm.php b/core/modules/system/src/Form/DateFormatDeleteForm.php
index 805bcce..7ba8f7d 100644
--- a/core/modules/system/src/Form/DateFormatDeleteForm.php
+++ b/core/modules/system/src/Form/DateFormatDeleteForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Datetime\Date as DateFormatter;
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -70,7 +71,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message(t('Removed date format %format.', array('%format' => $this->entity->label())));
 
diff --git a/core/modules/system/src/Form/DateFormatEditForm.php b/core/modules/system/src/Form/DateFormatEditForm.php
index c6a8eb0..84fda1c 100644
--- a/core/modules/system/src/Form/DateFormatEditForm.php
+++ b/core/modules/system/src/Form/DateFormatEditForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\system\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Provides a form for editing a date format.
  */
@@ -15,7 +17,7 @@ class DateFormatEditForm extends DateFormatFormBase {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
     $now = t('Displayed as %date', array('%date' => $this->dateFormatter->format(REQUEST_TIME, $this->entity->id())));
@@ -28,7 +30,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = t('Save format');
     unset($actions['delete']);
@@ -38,7 +40,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
     drupal_set_message(t('Custom date format updated.'));
   }
diff --git a/core/modules/system/src/Form/DateFormatFormBase.php b/core/modules/system/src/Form/DateFormatFormBase.php
index 3370fc1..edb2641 100644
--- a/core/modules/system/src/Form/DateFormatFormBase.php
+++ b/core/modules/system/src/Form/DateFormatFormBase.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
 use Drupal\Core\Datetime\Date as DateFormatter;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
@@ -67,13 +68,11 @@ public static function create(ContainerInterface $container) {
    *   The entity ID.
    * @param array $element
    *   The form element.
-   * @param array $form_state
-   *   The form state.
    *
    * @return bool
    *   TRUE if this format already exists, FALSE otherwise.
    */
-  public function exists($entity_id, array $element,  array $form_state) {
+  public function exists($entity_id, array $element) {
     return (bool) $this->dateFormatStorage
       ->getQuery()
       ->condition('id', $element['#field_prefix'] . $entity_id)
@@ -85,13 +84,13 @@ public function exists($entity_id, array $element,  array $form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   An AJAX Response to update the date-time value of the date format.
    */
-  public static function dateTimeLookup(array $form, array $form_state) {
+  public static function dateTimeLookup(array $form, FormStateInterface $form_state) {
     $format = '';
     if (!empty($form_state['values']['date_format_pattern'])) {
       $format = t('Displayed as %date_format', array('%date_format' => \Drupal::service('date')->format(REQUEST_TIME, 'custom', $form_state['values']['date_format_pattern'])));
@@ -107,7 +106,7 @@ public static function dateTimeLookup(array $form, array $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['label'] = array(
       '#type' => 'textfield',
       '#title' => 'Name',
@@ -156,7 +155,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     // The machine name field should already check to see if the requested
@@ -174,7 +173,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $form_state['redirect_route']['route_name'] = 'system.date_format_list';
     $form_state['values']['pattern'] = trim($form_state['values']['date_format_pattern']);
 
diff --git a/core/modules/system/src/Form/FileSystemForm.php b/core/modules/system/src/Form/FileSystemForm.php
index d7b1ad5..d2429e5 100644
--- a/core/modules/system/src/Form/FileSystemForm.php
+++ b/core/modules/system/src/Form/FileSystemForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Datetime\Date as DateFormatter;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Form\ConfigFormBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -59,7 +60,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.file');
     $form['file_public_path'] = array(
       '#type' => 'item',
@@ -119,7 +120,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $config = $this->config('system.file')
       ->set('path.private', $form_state['values']['file_private_path'])
       ->set('path.temporary', $form_state['values']['file_temporary_path'])
diff --git a/core/modules/system/src/Form/ImageToolkitForm.php b/core/modules/system/src/Form/ImageToolkitForm.php
index be00cd8..15378db 100644
--- a/core/modules/system/src/Form/ImageToolkitForm.php
+++ b/core/modules/system/src/Form/ImageToolkitForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\ImageToolkit\ImageToolkitManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -60,7 +61,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $current_toolkit = $this->config('system.image')->get('toolkit');
 
     $form['image_toolkit'] = array(
@@ -95,7 +96,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.image')
       ->set('toolkit', $form_state['values']['image_toolkit'])
       ->save();
diff --git a/core/modules/system/src/Form/LoggingForm.php b/core/modules/system/src/Form/LoggingForm.php
index f52fc6a..ddb7e3c 100644
--- a/core/modules/system/src/Form/LoggingForm.php
+++ b/core/modules/system/src/Form/LoggingForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure logging settings for this site.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.logging');
     $form['error_level'] = array(
       '#type' => 'radios',
@@ -45,7 +46,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.logging')
       ->set('error_level', $form_state['values']['error_level'])
       ->save();
diff --git a/core/modules/system/src/Form/ModulesListConfirmForm.php b/core/modules/system/src/Form/ModulesListConfirmForm.php
index fd671ee..412c4ba 100644
--- a/core/modules/system/src/Form/ModulesListConfirmForm.php
+++ b/core/modules/system/src/Form/ModulesListConfirmForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -101,7 +102,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $account = $this->currentUser()->id();
     $this->modules = $this->keyValueExpirable->get($account);
 
@@ -131,7 +132,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Remove the key value store entry.
     $account = $this->currentUser()->id();
     $this->keyValueExpirable->delete($account);
diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php
index e25070f..b12c4d2 100644
--- a/core/modules/system/src/Form/ModulesListForm.php
+++ b/core/modules/system/src/Form/ModulesListForm.php
@@ -9,18 +9,21 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Controller\TitleResolverInterface;
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\Query\QueryFactory;
-use Drupal\Core\Entity\Query\QueryFactoryInterface;
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
+use Drupal\Core\Menu\MenuLinkManagerInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Provides module installation interface.
@@ -61,11 +64,18 @@ class ModulesListForm extends FormBase {
   protected $entityManager;
 
   /**
-   * The query factory.
+   * The title resolver.
    *
-   * @var \Drupal\Core\Entity\Query\QueryFactory
+   * @var \Drupal\Core\Controller\TitleResolverInterface
    */
-  protected $queryFactory;
+  protected $titleResolver;
+
+  /**
+   * The route provider.
+   *
+   * @var \Drupal\Core\Routing\RouteProviderInterface
+   */
+  protected $routeProvider;
 
   /**
    * The current route match.
@@ -75,6 +85,13 @@ class ModulesListForm extends FormBase {
   protected $routeMatch;
 
   /**
+   * The menu link manager.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface
+   */
+  protected $menuLinkManager;
+
+  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
@@ -83,9 +100,11 @@ public static function create(ContainerInterface $container) {
       $container->get('keyvalue.expirable')->get('module_list'),
       $container->get('access_manager'),
       $container->get('entity.manager'),
-      $container->get('entity.query'),
       $container->get('current_user'),
-      $container->get('current_route_match')
+      $container->get('current_route_match'),
+      $container->get('title_resolver'),
+      $container->get('router.route_provider'),
+      $container->get('plugin.manager.menu.link')
     );
   }
 
@@ -100,21 +119,27 @@ public static function create(ContainerInterface $container) {
    *   Access manager.
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
-   * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
-   *   The entity query factory.
    * @param \Drupal\Core\Session\AccountInterface $current_user
    *   The current user.
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    *   The current route match.
+   * @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver
+   *   The title resolver.
+   * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
+   *   The route provider.
+   * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
+   *   The menu link manager.
    */
-  public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, AccessManagerInterface $access_manager, EntityManagerInterface $entity_manager, QueryFactory $query_factory, AccountInterface $current_user, RouteMatchInterface $route_match) {
+  public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, AccessManagerInterface $access_manager, EntityManagerInterface $entity_manager, AccountInterface $current_user,  RouteMatchInterface $route_match, TitleResolverInterface $title_resolver, RouteProviderInterface $route_provider, MenuLinkManagerInterface $menu_link_manager) {
     $this->moduleHandler = $module_handler;
     $this->keyValueExpirable = $key_value_expirable;
     $this->accessManager = $access_manager;
     $this->entityManager = $entity_manager;
-    $this->queryFactory = $query_factory;
     $this->currentUser = $current_user;
     $this->routeMatch = $route_match;
+    $this->titleResolver = $title_resolver;
+    $this->routeProvider = $route_provider;
+    $this->menuLinkManager = $menu_link_manager;
   }
 
   /**
@@ -127,7 +152,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     require_once DRUPAL_ROOT . '/core/includes/install.inc';
     $distribution = String::checkPlain(drupal_install_profile_distribution_name());
 
@@ -249,11 +274,23 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
     if ($module->status && isset($module->info['configure'])) {
       $route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array();
       if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) {
-        $result = $this->queryFactory->get('menu_link')
-          ->condition('route_name', $module->info['configure'])
-          ->execute();
-        $menu_items = $this->entityManager->getStorage('menu_link')->loadMultiple($result);
-        $item = reset($menu_items);
+
+        $links = $this->menuLinkManager->loadLinksByRoute($module->info['configure']);
+        /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
+        $link = reset($links);
+        // Most configure links have a corresponding menu link, though some just
+        // have a route.
+        if ($link) {
+          $description = $link->getDescription();
+        }
+        else {
+          $request = new Request();
+          $request->attributes->set('_route_name', $module->info['configure']);
+          $route_object = $this->routeProvider->getRouteByName($module->info['configure']);
+          $request->attributes->set('_route', $route_object);
+          $description = $this->titleResolver->getTitle($request, $route_object);
+        }
+
         $row['links']['configure'] = array(
           '#type' => 'link',
           '#title' => $this->t('Configure'),
@@ -262,7 +299,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
           '#options' => array(
             'attributes' => array(
               'class' => array('module-link', 'module-link-configure'),
-              'title' => $item['description'],
+              'title' => $description,
             ),
           ),
         );
@@ -372,13 +409,13 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
   /**
    * Helper function for building a list of modules to install.
    *
-   * @param array $form_state
-   *   The form state array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   An array of modules to install and their dependencies.
    */
-  protected function buildModuleList(array $form_state) {
+  protected function buildModuleList($form_state) {
     $packages = $form_state['values']['modules'];
 
     // Build a list of modules to install.
@@ -436,7 +473,7 @@ protected function buildModuleList(array $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Retrieve a list of modules to install and their dependencies.
     $modules = $this->buildModuleList($form_state);
 
diff --git a/core/modules/system/src/Form/ModulesUninstallConfirmForm.php b/core/modules/system/src/Form/ModulesUninstallConfirmForm.php
index 1825d53..02c1dbe 100644
--- a/core/modules/system/src/Form/ModulesUninstallConfirmForm.php
+++ b/core/modules/system/src/Form/ModulesUninstallConfirmForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Config\ConfigManagerInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -125,7 +126,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Retrieve the list of modules from the key value store.
     $account = $this->currentUser()->id();
     $this->modules = $this->keyValueExpirable->get($account);
@@ -191,7 +192,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Clear the key value store entry.
     $account = $this->currentUser()->id();
     $this->keyValueExpirable->delete($account);
diff --git a/core/modules/system/src/Form/ModulesUninstallForm.php b/core/modules/system/src/Form/ModulesUninstallForm.php
index 7438e48..b1ec48c 100644
--- a/core/modules/system/src/Form/ModulesUninstallForm.php
+++ b/core/modules/system/src/Form/ModulesUninstallForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -64,7 +65,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Make sure the install API is available.
     include_once DRUPAL_ROOT . '/core/includes/install.inc';
 
@@ -148,7 +149,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Form submitted, but no modules selected.
     if (!array_filter($form_state['values']['uninstall'])) {
       drupal_set_message($this->t('No modules selected.'), 'error');
@@ -159,7 +160,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Save all the values in an expirable key value store.
     $modules = $form_state['values']['uninstall'];
     $uninstall = array_keys(array_filter($modules));
diff --git a/core/modules/system/src/Form/PerformanceForm.php b/core/modules/system/src/Form/PerformanceForm.php
index 2431e78..d208cc3 100644
--- a/core/modules/system/src/Form/PerformanceForm.php
+++ b/core/modules/system/src/Form/PerformanceForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Datetime\Date as DateFormatter;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -69,7 +70,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#attached']['library'][] = 'system/drupal.system';
 
     $config = $this->config('system.performance');
@@ -155,7 +156,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_clear_css_cache();
     drupal_clear_js_cache();
     // This form allows page compression settings to be changed, which can
@@ -177,7 +178,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Clears the caches.
    */
-  public function submitCacheClear(array &$form, array &$form_state) {
+  public function submitCacheClear(array &$form, FormStateInterface $form_state) {
     drupal_flush_all_caches();
     drupal_set_message(t('Caches cleared.'));
   }
diff --git a/core/modules/system/src/Form/RegionalForm.php b/core/modules/system/src/Form/RegionalForm.php
index d361859..7ac2159 100644
--- a/core/modules/system/src/Form/RegionalForm.php
+++ b/core/modules/system/src/Form/RegionalForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Locale\CountryManagerInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -57,7 +58,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $countries = $this->countryManager->getList();
     $system_date = $this->config('system.date');
 
@@ -141,7 +142,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.date')
       ->set('country.default', $form_state['values']['site_default_country'])
       ->set('first_day', $form_state['values']['date_first_day'])
diff --git a/core/modules/system/src/Form/RssFeedsForm.php b/core/modules/system/src/Form/RssFeedsForm.php
index e487fce..5ba8e6d 100644
--- a/core/modules/system/src/Form/RssFeedsForm.php
+++ b/core/modules/system/src/Form/RssFeedsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure RSS settings for this site.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $rss_config = $this->config('system.rss');
     $form['feed_description'] = array(
       '#type' => 'textarea',
@@ -58,7 +59,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.rss')
       ->set('channel.description', $form_state['values']['feed_description'])
       ->set('items.limit', $form_state['values']['feed_default_items'])
diff --git a/core/modules/system/src/Form/SiteInformationForm.php b/core/modules/system/src/Form/SiteInformationForm.php
index c2b9c67..46b9013 100644
--- a/core/modules/system/src/Form/SiteInformationForm.php
+++ b/core/modules/system/src/Form/SiteInformationForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Path\AliasManagerInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -58,7 +59,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $site_config = $this->config('system.site');
     $site_mail = $site_config->get('mail');
     if (empty($site_mail)) {
@@ -131,7 +132,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Check for empty front page path.
     if (empty($form_state['values']['site_frontpage'])) {
       // Set to default "user".
@@ -167,7 +168,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.site')
       ->set('name', $form_state['values']['site_name'])
       ->set('mail', $form_state['values']['site_mail'])
diff --git a/core/modules/system/src/Form/SiteMaintenanceModeForm.php b/core/modules/system/src/Form/SiteMaintenanceModeForm.php
index 7de4e61..1ee0aa6 100644
--- a/core/modules/system/src/Form/SiteMaintenanceModeForm.php
+++ b/core/modules/system/src/Form/SiteMaintenanceModeForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\Form\ConfigFormBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -56,7 +57,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('system.maintenance');
     $form['maintenance_mode'] = array(
       '#type' => 'checkbox',
@@ -76,7 +77,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('system.maintenance')
       ->set('message', $form_state['values']['maintenance_mode_message'])
       ->save();
diff --git a/core/modules/system/src/Form/ThemeAdminForm.php b/core/modules/system/src/Form/ThemeAdminForm.php
index d836047..627c2b3 100644
--- a/core/modules/system/src/Form/ThemeAdminForm.php
+++ b/core/modules/system/src/Form/ThemeAdminForm.php
@@ -7,6 +7,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form to select the administration theme.
@@ -23,7 +24,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, array $theme_options = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, array $theme_options = NULL) {
     // Administration theme settings.
     $form['admin_theme'] = array(
       '#type' => 'details',
@@ -48,7 +49,7 @@ public function buildForm(array $form, array &$form_state, array $theme_options
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The configuration options have been saved.'));
     $this->config('system.theme')->set('admin', $form_state['values']['admin_theme'])->save();
   }
diff --git a/core/modules/system/src/Form/ThemeSettingsForm.php b/core/modules/system/src/Form/ThemeSettingsForm.php
index 7752960..9d398d9 100644
--- a/core/modules/system/src/Form/ThemeSettingsForm.php
+++ b/core/modules/system/src/Form/ThemeSettingsForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -65,7 +66,7 @@ public function getFormId() {
    * @param string $theme
    *   The theme name.
    */
-  public function buildForm(array $form, array &$form_state, $theme = '') {
+  public function buildForm(array $form, FormStateInterface $form_state, $theme = '') {
     $form = parent::buildForm($form, $form_state);
 
     $themes = list_themes();
@@ -316,7 +317,7 @@ public function buildForm(array $form, array &$form_state, $theme = '') {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     parent::validateForm($form, $form_state);
 
     if ($this->moduleHandler->moduleExists('file')) {
@@ -373,7 +374,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     $config = $this->config($form_state['values']['config_key']);
diff --git a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
index 13e1b7f..0cecf2b 100644
--- a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\block\BlockBase;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -105,7 +106,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     // Get the theme.
     $theme = $form_state['block_theme'];
 
@@ -173,7 +174,7 @@ public function blockForm($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     $this->configuration['use_site_logo'] = $form_state['values']['block_branding']['use_site_logo'];
     $this->configuration['use_site_name'] = $form_state['values']['block_branding']['use_site_name'];
     $this->configuration['use_site_slogan'] = $form_state['values']['block_branding']['use_site_slogan'];
diff --git a/core/modules/system/src/Plugin/Block/SystemMainBlock.php b/core/modules/system/src/Plugin/Block/SystemMainBlock.php
index 666b515..e251cad 100644
--- a/core/modules/system/src/Plugin/Block/SystemMainBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemMainBlock.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Plugin\Block;
 
 use Drupal\block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a 'Main page content' block.
@@ -31,7 +32,7 @@ public function build() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
     // The main content block is never cacheable, because it may be dynamic.
diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
index 5381471..258ffbb 100644
--- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
@@ -10,7 +10,8 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\block\BlockBase;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\menu_link\MenuTreeInterface;
+use Drupal\Core\Menu\MenuActiveTrailInterface;
+use Drupal\Core\Menu\MenuLinkTreeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 
@@ -27,13 +28,20 @@
 class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
   /**
-   * The menu tree.
+   * The menu link tree service.
    *
-   * @var \Drupal\menu_link\MenuTreeInterface
+   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
    */
   protected $menuTree;
 
   /**
+   * The active menu trail service.
+   *
+   * @var \Drupal\Core\Menu\MenuActiveTrailInterface
+   */
+  protected $menuActiveTrail;
+
+  /**
    * Constructs a new SystemMenuBlock.
    *
    * @param array $configuration
@@ -42,12 +50,15 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
    *   The plugin_id for the plugin instance.
    * @param array $plugin_definition
    *   The plugin implementation definition.
-   * @param \Drupal\menu_link\MenuTreeInterface $menu_tree
-   *   The menu tree.
+   * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
+   *   The menu tree service.
+   * @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
+   *   The active menu trail service.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuTreeInterface $menu_tree) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->menuTree = $menu_tree;
+    $this->menuActiveTrail = $menu_active_trail;
   }
 
   /**
@@ -58,7 +69,8 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('menu_link.tree')
+      $container->get('menu.link_tree'),
+      $container->get('menu.active_trail')
     );
   }
 
@@ -66,8 +78,15 @@ public static function create(ContainerInterface $container, array $configuratio
    * {@inheritdoc}
    */
   public function build() {
-    $menu = $this->getDerivativeId();
-    return $this->menuTree->renderMenu($menu);
+    $menu_name = $this->getDerivativeId();
+    $parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name);
+    $tree = $this->menuTree->load($menu_name, $parameters);
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+      array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    );
+    $tree = $this->menuTree->transform($tree, $manipulators);
+    return $this->menuTree->build($tree);
   }
 
   /**
@@ -91,9 +110,7 @@ public function defaultConfiguration() {
   public function getCacheKeys() {
     // Add a key for the active menu trail.
     $menu = $this->getDerivativeId();
-    $active_trail = $this->menuTree->getActiveTrailIds($menu);
-    $active_trail_key = 'trail.' . implode('|', $active_trail);
-    return array_merge(parent::getCacheKeys(), array($active_trail_key));
+    return array_merge(parent::getCacheKeys(), array($this->menuActiveTrail->getActiveTrailCacheKey($menu)));
   }
 
   /**
@@ -114,7 +131,7 @@ public function getCacheTags() {
   protected function getRequiredCacheContexts() {
     // Menu blocks must be cached per role: different roles may have access to
     // different menu links.
-    return array('cache_context.user.roles');
+    return array('cache_context.user.roles', 'cache_context.language');
   }
 
 }
diff --git a/core/modules/system/src/Plugin/Block/SystemPoweredByBlock.php b/core/modules/system/src/Plugin/Block/SystemPoweredByBlock.php
index 2b4ffaa..980d5b3 100644
--- a/core/modules/system/src/Plugin/Block/SystemPoweredByBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemPoweredByBlock.php
@@ -9,6 +9,7 @@
 
 use Drupal\block\BlockBase;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a 'Powered by Drupal' block.
@@ -27,11 +28,10 @@ public function build() {
     return array('#markup' => '<span>' . t('Powered by <a href="@poweredby">Drupal</a>', array('@poweredby' => 'https://drupal.org')) . '</span>');
   }
 
-
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
     // The 'Powered by Drupal' block is permanently cacheable, because its
diff --git a/core/modules/system/src/Plugin/Condition/CurrentThemeCondition.php b/core/modules/system/src/Plugin/Condition/CurrentThemeCondition.php
index 874bcd6..1ccd1f9 100644
--- a/core/modules/system/src/Plugin/Condition/CurrentThemeCondition.php
+++ b/core/modules/system/src/Plugin/Condition/CurrentThemeCondition.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Condition\ConditionPluginBase;
 use Drupal\Core\Extension\ThemeHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Theme\ThemeNegotiatorInterface;
@@ -92,7 +93,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['theme'] = array(
       '#type' => 'select',
       '#title' => $this->t('Theme'),
@@ -107,7 +108,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['theme'] = $form_state['values']['theme'];
     parent::submitConfigurationForm($form, $form_state);
   }
diff --git a/core/modules/system/src/Plugin/Condition/RequestPath.php b/core/modules/system/src/Plugin/Condition/RequestPath.php
index 1dab54f..c6314d5 100644
--- a/core/modules/system/src/Plugin/Condition/RequestPath.php
+++ b/core/modules/system/src/Plugin/Condition/RequestPath.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Condition\ConditionPluginBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Path\AliasManagerInterface;
 use Drupal\Core\Path\PathMatcherInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -93,7 +94,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['pages'] = array(
       '#type' => 'textarea',
       '#title' => $this->t('Pages'),
@@ -110,7 +111,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['pages'] = $form_state['values']['pages'];
     parent::submitConfigurationForm($form, $form_state);
   }
diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
index c1a29a6..3cbdbd9 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Plugin\ImageToolkit;
 
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\ImageToolkit\ImageToolkitBase;
 
 /**
@@ -76,7 +77,7 @@ public function settingsForm() {
   /**
    * {@inheritdoc}
    */
-  public function settingsFormSubmit($form, &$form_state) {
+  public function settingsFormSubmit($form, FormStateInterface $form_state) {
     \Drupal::config('system.image.gd')
       ->set('jpeg_quality', $form_state['values']['gd']['image_jpeg_quality'])
       ->save();
diff --git a/core/modules/system/src/Plugin/views/field/BulkForm.php b/core/modules/system/src/Plugin/views/field/BulkForm.php
index fc9898d..9cf6836 100644
--- a/core/modules/system/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/system/src/Plugin/views/field/BulkForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\style\Table;
@@ -92,7 +93,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['action_title'] = array(
       '#type' => 'textfield',
       '#title' => t('Action title'),
@@ -122,7 +123,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     parent::validateOptionsForm($form, $form_state);
 
     $form_state['values']['options']['selected_actions'] = array_filter($form_state['values']['options']['selected_actions']);
@@ -157,10 +158,10 @@ public function preRender(&$values) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function viewsForm(&$form, &$form_state) {
+  public function viewsForm(&$form, FormStateInterface $form_state) {
     // Add the tableselect javascript.
     $form['#attached']['library'][] = 'core/drupal.tableselect';
 
@@ -245,10 +246,10 @@ protected function getBulkOptions($filtered = TRUE) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function viewsFormSubmit(&$form, &$form_state) {
+  public function viewsFormSubmit(&$form, FormStateInterface $form_state) {
     if ($form_state['step'] == 'views_form_views_form') {
       // Filter only selected checkboxes.
       $selected = array_filter($form_state['values'][$this->options['id']]);
@@ -289,7 +290,7 @@ protected function emptySelectedMessage() {
   /**
    * {@inheritdoc}
    */
-  public function viewsFormValidate(&$form, &$form_state) {
+  public function viewsFormValidate(&$form, FormStateInterface $form_state) {
     $selected = array_filter($form_state['values'][$this->options['id']]);
     if (empty($selected)) {
       form_set_error('', $form_state, $this->emptySelectedMessage());
diff --git a/core/modules/system/src/SystemManager.php b/core/modules/system/src/SystemManager.php
index 696efc1..00f97aa 100644
--- a/core/modules/system/src/SystemManager.php
+++ b/core/modules/system/src/SystemManager.php
@@ -6,8 +6,11 @@
 
 namespace Drupal\system;
 
-use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Menu\MenuActiveTrailInterface;
+use Drupal\Core\Menu\MenuLinkTreeInterface;
+use Drupal\Core\Menu\MenuLinkInterface;
+use Drupal\Core\Menu\MenuTreeParameters;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -33,18 +36,25 @@ class SystemManager {
   protected $database;
 
   /**
-   * The menu link storage.
+   * The request stack.
    *
-   * @var \Drupal\menu_link\MenuLinkStorageInterface
+   * @var \Symfony\Component\HttpFoundation\RequestStack
    */
-  protected $menuLinkStorage;
+  protected $requestStack;
 
   /**
-   * The request stack.
+   * The menu link tree manager.
    *
-   * @var \Symfony\Component\HttpFoundation\RequestStack
+   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
    */
-  protected $requestStack;
+  protected $menuTree;
+
+  /**
+   * The active menu trail service.
+   *
+   * @var \Drupal\Core\Menu\MenuActiveTrailInterface
+   */
+  protected $menuActiveTrail;
 
   /**
    * A static cache of menu items.
@@ -79,12 +89,17 @@ class SystemManager {
    *   The entity manager.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
+   * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
+   *   The menu tree manager.
+   * @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
+   *   The active menu trail service.
    */
-  public function __construct(ModuleHandlerInterface $module_handler, Connection $database, EntityManagerInterface $entity_manager, RequestStack $request_stack) {
+  public function __construct(ModuleHandlerInterface $module_handler, Connection $database, EntityManagerInterface $entity_manager, RequestStack $request_stack, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
     $this->moduleHandler = $module_handler;
     $this->database = $database;
-    $this->menuLinkStorage = $entity_manager->getStorage('menu_link');
     $this->requestStack = $request_stack;
+    $this->menuTree = $menu_tree;
+    $this->menuActiveTrail = $menu_active_trail;
   }
 
   /**
@@ -171,11 +186,10 @@ public function getMaxSeverity(&$requirements) {
    *   A render array suitable for drupal_render.
    */
   public function getBlockContents() {
-    $request = $this->requestStack->getCurrentRequest();
-    $route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
-    $items = $this->menuLinkStorage->loadByProperties(array('route_name' => $route_name));
-    $item = reset($items);
-    if ($content = $this->getAdminBlock($item)) {
+    // We hard-code the menu name here since otherwise a link in the tools menu
+    // or elsewhere could give us a blank block.
+    $link = $this->menuActiveTrail->getActiveLink('admin');
+    if ($link && $content = $this->getAdminBlock($link)) {
       $output = array(
         '#theme' => 'admin_block_content',
         '#content' => $content,
@@ -192,48 +206,33 @@ public function getBlockContents() {
   /**
    * Provide a single block on the administration overview page.
    *
-   * @param \Drupal\menu_link\MenuLinkInterface|array $item
+   * @param \Drupal\Core\Menu\MenuLinkInterface $instance
    *   The menu item to be displayed.
    *
    * @return array
    *   An array of menu items, as expected by theme_admin_block_content().
    */
-  public function getAdminBlock($item) {
-    if (!isset($item['mlid'])) {
-      $menu_links = $this->menuLinkStorage->loadByProperties(array('link_path' => $item['path'], 'module' => 'system'));
-      if ($menu_links) {
-        $menu_link = reset($menu_links);
-        $item['mlid'] = $menu_link->id();
-        $item['menu_name'] = $menu_link->menu_name;
-      }
-      else {
-        return array();
-      }
-    }
-
-    if (isset($this->menuItems[$item['mlid']])) {
-      return $this->menuItems[$item['mlid']];
-    }
-
+  public function getAdminBlock(MenuLinkInterface $instance) {
     $content = array();
-    $menu_links = $this->menuLinkStorage->loadByProperties(array('plid' => $item['mlid'], 'menu_name' => $item['menu_name'], 'hidden' => 0));
-    foreach ($menu_links as $link) {
-      _menu_link_translate($link);
-      if ($link['access']) {
-        // The link description, either derived from 'description' in
-        // hook_menu() or customized via Menu UI module is used as title attribute.
-        if (!empty($link['localized_options']['attributes']['title'])) {
-          $link['description'] = $link['localized_options']['attributes']['title'];
-          unset($link['localized_options']['attributes']['title']);
-        }
-        // Prepare for sorting as in function _menu_tree_check_access().
-        // The weight is offset so it is always positive, with a uniform 5-digits.
-        $key = (50000 + $link['weight']) . ' ' . Unicode::strtolower($link['title']) . ' ' . $link['mlid'];
-        $content[$key] = $link;
-      }
+    // Only find the children of this link.
+    $link_id = $instance->getPluginId();
+    $parameters = new MenuTreeParameters();
+    $parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
+    $tree = $this->menuTree->load(NULL, $parameters);
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+      array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    );
+    $tree = $this->menuTree->transform($tree, $manipulators);
+    foreach ($tree as $key => $element) {
+      /** @var $link \Drupal\Core\Menu\MenuLinkInterface */
+      $link = $element->link;
+      $content[$key]['title'] = $link->getTitle();
+      $content[$key]['options'] = $link->getOptions();
+      $content[$key]['description'] = $link->getDescription();
+      $content[$key]['url'] = $link->getUrlObject();
     }
     ksort($content);
-    $this->menuItems[$item['mlid']] = $content;
     return $content;
   }
 
diff --git a/core/modules/system/src/Tests/Form/ElementsTableSelectTest.php b/core/modules/system/src/Tests/Form/ElementsTableSelectTest.php
index b0ce2f8..0ca830a 100644
--- a/core/modules/system/src/Tests/Form/ElementsTableSelectTest.php
+++ b/core/modules/system/src/Tests/Form/ElementsTableSelectTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Form;
 
+use Drupal\Core\Form\FormState;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -207,7 +208,7 @@ function testMultipleFalseOptionchecker() {
    */
   private function formSubmitHelper($form, $edit) {
     $form_id = $this->randomName();
-    $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $form_state = new FormState();
 
     $form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
     // The form token CSRF protection should not interfere with this test, so we
diff --git a/core/modules/system/src/Tests/Form/FormCacheTest.php b/core/modules/system/src/Tests/Form/FormCacheTest.php
index b33c749..f8056ba 100644
--- a/core/modules/system/src/Tests/Form/FormCacheTest.php
+++ b/core/modules/system/src/Tests/Form/FormCacheTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Form;
 
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Session\UserSession;
 use Drupal\simpletest\DrupalUnitTestBase;
 
@@ -32,7 +33,7 @@ public function setUp() {
     $this->form = array(
       '#property' => $this->randomName(),
     );
-    $this->form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $this->form_state = new FormState();
     $this->form_state['example'] = $this->randomName();
   }
 
@@ -43,7 +44,7 @@ function testCacheToken() {
     \Drupal::currentUser()->setAccount(new UserSession(array('uid' => 1)));
     form_set_cache($this->form_build_id, $this->form, $this->form_state);
 
-    $cached_form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $cached_form_state = new FormState();
     $cached_form = form_get_cache($this->form_build_id, $cached_form_state);
     $this->assertEqual($this->form['#property'], $cached_form['#property']);
     $this->assertTrue(!empty($cached_form['#cache_token']), 'Form has a cache token');
@@ -53,14 +54,14 @@ function testCacheToken() {
     // Change the private key. (We cannot change the session ID because this
     // will break the parent site test runner batch.)
     \Drupal::state()->set('system.private_key', 'invalid');
-    $cached_form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $cached_form_state = new FormState();
     $cached_form = form_get_cache($this->form_build_id, $cached_form_state);
     $this->assertFalse($cached_form, 'No form returned from cache');
     $this->assertTrue(empty($cached_form_state['example']));
 
     // Test that loading the cache with a different form_id fails.
     $wrong_form_build_id = $this->randomName(9);
-    $cached_form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $cached_form_state = new FormState();
     $this->assertFalse(form_get_cache($wrong_form_build_id, $cached_form_state), 'No form returned from cache');
     $this->assertTrue(empty($cached_form_state['example']), 'Cached form state was not loaded');
   }
@@ -74,7 +75,7 @@ function testNoCacheToken() {
     $this->form_state['example'] = $this->randomName();
     form_set_cache($this->form_build_id, $this->form, $this->form_state);
 
-    $cached_form_state = \Drupal::formBuilder()->getFormStateDefaults();
+    $cached_form_state = new FormState();
     $cached_form = form_get_cache($this->form_build_id, $cached_form_state);
     $this->assertEqual($this->form['#property'], $cached_form['#property']);
     $this->assertTrue(empty($cached_form['#cache_token']), 'Form has no cache token');
diff --git a/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php b/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php
index 9c980a6..7fa6a7c 100644
--- a/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php
+++ b/core/modules/system/src/Tests/Form/FormDefaultHandlersTest.php
@@ -8,6 +8,8 @@
 namespace Drupal\system\Tests\Form;
 
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\simpletest\KernelTestBase;
 
 /**
@@ -34,7 +36,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['#validate'][] = array($this, 'customValidateForm');
     $form['#submit'][] = array($this, 'customSubmitForm');
     $form['submit'] = array('#type' => 'submit', '#value' => 'Save');
@@ -44,28 +46,28 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function customValidateForm(array &$form, array &$form_state) {
+  public function customValidateForm(array &$form, FormStateInterface $form_state) {
     $form_state['test_handlers']['validate'][] = __FUNCTION__;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state['test_handlers']['validate'][] = __FUNCTION__;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function customSubmitForm(array &$form, array &$form_state) {
+  public function customSubmitForm(array &$form, FormStateInterface $form_state) {
     $form_state['test_handlers']['submit'][] = __FUNCTION__;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['test_handlers']['submit'][] = __FUNCTION__;
   }
 
@@ -73,7 +75,7 @@ public function submitForm(array &$form, array &$form_state) {
    * Tests that default handlers are added even if custom are specified.
    */
   function testDefaultAndCustomHandlers() {
-    $form_state['values'] = array();
+    $form_state = new FormState(array('values' => array()));
     $form_builder = $this->container->get('form_builder');
     $form_builder->submitForm($this, $form_state);
 
diff --git a/core/modules/system/src/Tests/Form/FormTest.php b/core/modules/system/src/Tests/Form/FormTest.php
index 2b4850e..12d78ea 100644
--- a/core/modules/system/src/Tests/Form/FormTest.php
+++ b/core/modules/system/src/Tests/Form/FormTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Render\Element;
 use Drupal\form_test\Form\FormTestDisabledElementsForm;
 use Drupal\simpletest\WebTestBase;
@@ -102,7 +103,7 @@ function testRequiredFields() {
         foreach (array(TRUE, FALSE) as $required) {
           $form_id = $this->randomName();
           $form = array();
-          $form_state = \Drupal::formBuilder()->getFormStateDefaults();
+          $form_state = new FormState();
           $form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
           $element = $data['element']['#title'];
           $form[$element] = $data['element'];
@@ -482,7 +483,7 @@ function testColorValidation() {
    */
   function testDisabledElements() {
     // Get the raw form in its original state.
-    $form_state = array();
+    $form_state = new FormState();
     $form = (new FormTestDisabledElementsForm())->buildForm(array(), $form_state);
 
     // Build a submission that tries to hijack the form by submitting input for
diff --git a/core/modules/system/src/Tests/Form/ProgrammaticTest.php b/core/modules/system/src/Tests/Form/ProgrammaticTest.php
index a5c4071..2eba5ea 100644
--- a/core/modules/system/src/Tests/Form/ProgrammaticTest.php
+++ b/core/modules/system/src/Tests/Form/ProgrammaticTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Form;
 
+use Drupal\Core\Form\FormState;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -71,7 +72,7 @@ function testSubmissionWorkflow() {
    */
   private function submitForm($values, $valid_input) {
     // Programmatically submit the given values.
-    $form_state = array('values' => $values);
+    $form_state = new FormState(array('values' => $values));
     \Drupal::formBuilder()->submitForm('\Drupal\form_test\Form\FormTestProgrammaticForm', $form_state);
 
     // Check that the form returns an error when expected, and vice versa.
@@ -98,6 +99,7 @@ private function submitForm($values, $valid_input) {
    * Test the programmed_bypass_access_check flag.
    */
   public function testProgrammaticAccessBypass() {
+    $form_state = new FormState();
     $form_state['values'] = array(
       'textfield' => 'dummy value',
       'field_restricted' => 'dummy value'
diff --git a/core/modules/system/src/Tests/Form/StubForm.php b/core/modules/system/src/Tests/Form/StubForm.php
index 225371b..c3898df 100644
--- a/core/modules/system/src/Tests/Form/StubForm.php
+++ b/core/modules/system/src/Tests/Form/StubForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Tests\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a stub form for testing purposes.
@@ -51,14 +52,14 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     return $this->form;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/src/Tests/Form/TriggeringElementProgrammedUnitTest.php b/core/modules/system/src/Tests/Form/TriggeringElementProgrammedUnitTest.php
index 3e6f413..2d040de 100644
--- a/core/modules/system/src/Tests/Form/TriggeringElementProgrammedUnitTest.php
+++ b/core/modules/system/src/Tests/Form/TriggeringElementProgrammedUnitTest.php
@@ -9,6 +9,8 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
@@ -30,7 +32,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['one'] = array(
       '#type' => 'textfield',
       '#title' => 'One',
@@ -57,7 +59,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     // Verify that the only submit button was recognized as triggering_element.
     $this->assertEqual($form['actions']['submit']['#array_parents'], $form_state['triggering_element']['#array_parents']);
   }
@@ -65,7 +67,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
@@ -73,6 +75,7 @@ public function submitForm(array &$form, array &$form_state) {
    */
   function testLimitValidationErrors() {
     // Programmatically submit the form.
+    $form_state = new FormState();
     $form_state['values'] = array();
     $form_state['values']['section'] = 'one';
     $form_builder = $this->container->get('form_builder');
diff --git a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
index f1bf640..ec6201a 100644
--- a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
+++ b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php
@@ -83,15 +83,10 @@ function testBreadCrumbs() {
     );
     $this->assertBreadcrumb('admin/structure/menu/manage/tools', $trail);
 
-    $mlid_node_add = \Drupal::entityQuery('menu_link')
-      ->condition('machine_name', 'node.add_page')
-      ->condition('module', 'node')
-      ->execute();
-    $mlid_node_add = reset($mlid_node_add);
     $trail += array(
       'admin/structure/menu/manage/tools' => t('Tools'),
     );
-    $this->assertBreadcrumb("admin/structure/menu/item/$mlid_node_add/edit", $trail);
+    $this->assertBreadcrumb("admin/structure/menu/link/node.add_page/edit", $trail);
     $this->assertBreadcrumb('admin/structure/menu/manage/tools/add', $trail);
 
     // Verify Node administration breadcrumbs.
@@ -165,7 +160,7 @@ function testBreadCrumbs() {
     // Alter node type menu settings.
     \Drupal::config("menu.entity.node.$type")
       ->set('available_menus', $menus)
-      ->set('parent', 'tools:0')
+      ->set('parent', 'tools:')
       ->save();
 
     foreach ($menus as $menu) {
@@ -174,13 +169,13 @@ function testBreadCrumbs() {
       $node2 = $this->drupalCreateNode(array(
         'type' => $type,
         'title' => $title,
-        'menu' => entity_create('menu_link', array(
-          'enabled' => 1,
-          'link_title' => 'Parent ' . $title,
+        'menu' => array(
+          'hidden' => 0,
+          'title' => 'Parent ' . $title,
           'description' => '',
           'menu_name' => $menu,
-          'plid' => 0,
-        )),
+          'parent' => '',
+        ),
       ));
 
       if ($menu == 'tools') {
@@ -192,26 +187,26 @@ function testBreadCrumbs() {
     // link below it, and verify a full breadcrumb for the last child node.
     $menu = 'tools';
     $edit = array(
-      'link_title' => 'Root',
-      'link_path' => 'node',
+      'title[0][value]' => 'Root',
+      'url' => 'node',
     );
     $this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => 'Root'));
+    $menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => 'Root'));
     $link = reset($menu_links);
 
     $edit = array(
-      'menu[parent]' => $link['menu_name'] . ':' . $link['mlid'],
+      'menu[menu_parent]' => $link->getMenuName() . ':' . $link->getPluginId(),
     );
     $this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save and keep published'));
     $expected = array(
-      "node" => $link['link_title'],
+      "node" => $link->getTitle(),
     );
     $trail = $home + $expected;
     $tree = $expected + array(
-      'node/' . $parent->id() => $parent->menu['link_title'],
+      'node/' . $parent->id() => $parent->menu['title'],
     );
     $trail += array(
-      'node/' . $parent->id() => $parent->menu['link_title'],
+      'node/' . $parent->id() => $parent->menu['title'],
     );
 
     // Add a taxonomy term/tag to last node, and add a link for that term to the
@@ -241,32 +236,36 @@ function testBreadCrumbs() {
       }
       $parent_tid = $term->id();
     }
-    $parent_mlid = 0;
+    $parent_mlid = '';
     foreach ($tags as $name => $data) {
       $term = $data['term'];
       $edit = array(
-        'link_title' => "$name link",
-        'link_path' => "taxonomy/term/{$term->id()}",
-        'parent' => "$menu:{$parent_mlid}",
+        'title[0][value]' => "$name link",
+        'url' => "taxonomy/term/{$term->id()}",
+        'menu_parent' => "$menu:{$parent_mlid}",
       );
       $this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
-      $menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $edit['link_title'], 'link_path' => $edit['link_path']));
+      $menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $edit['title[0][value]'], 'route_name' => 'taxonomy.term_page', 'route_parameters' => serialize(array('taxonomy_term' => $term->id()))));
       $tags[$name]['link'] = reset($menu_links);
-      $tags[$name]['link']['link_path'] = $edit['link_path'];
-      $parent_mlid = $tags[$name]['link']['mlid'];
+      $parent_mlid = $tags[$name]['link']->getPluginId();
     }
 
     // Verify expected breadcrumbs for menu links.
     $trail = $home;
     $tree = array();
+    // Logout the user because we want to check the active class as well, which
+    // is just rendered as anonymous user.
+    $this->drupalLogout();
     foreach ($tags as $name => $data) {
       $term = $data['term'];
+      /** @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface $link */
       $link = $data['link'];
 
+      $link_path = $link->getUrlObject()->getInternalPath();
       $tree += array(
-        $link['link_path'] => $link['link_title'],
+        $link_path => $link->getTitle(),
       );
-      $this->assertBreadcrumb($link['link_path'], $trail, $term->getName(), $tree);
+      $this->assertBreadcrumb($link_path, $trail, $term->getName(), $tree);
       $this->assertRaw(String::checkPlain($parent->getTitle()), 'Tagged node found.');
 
       // Additionally make sure that this link appears only once; i.e., the
@@ -275,14 +274,14 @@ function testBreadCrumbs() {
       // other than the breadcrumb trail.
       $elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array(
         ':menu' => 'block-bartik-tools',
-        ':href' => url($link['link_path']),
+        ':href' => url($link_path),
       ));
-      $this->assertTrue(count($elements) == 1, "Link to {$link['link_path']} appears only once.");
+      $this->assertTrue(count($elements) == 1, "Link to {$link_path} appears only once.");
 
       // Next iteration should expect this tag as parent link.
       // Note: Term name, not link name, due to taxonomy_term_page().
       $trail += array(
-        $link['link_path'] => $term->getName(),
+        $link_path => $term->getName(),
       );
     }
 
@@ -292,7 +291,6 @@ function testBreadCrumbs() {
     user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
       'access user profiles',
     ));
-    $this->drupalLogout();
 
     // Verify breadcrumb on front page.
     $this->assertBreadcrumb('<front>', array());
@@ -359,4 +357,5 @@ function testBreadCrumbs() {
     $this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages'));
     $this->assertNoResponse(403);
   }
+
 }
diff --git a/core/modules/system/src/Tests/Menu/LinksTest.php b/core/modules/system/src/Tests/Menu/LinksTest.php
index eecfb8c..552b1ae 100644
--- a/core/modules/system/src/Tests/Menu/LinksTest.php
+++ b/core/modules/system/src/Tests/Menu/LinksTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Menu;
 
+use Drupal\Component\Utility\String;
 use Drupal\locale\TranslationString;
 use Drupal\simpletest\WebTestBase;
 
@@ -14,6 +15,9 @@
  * Tests handling of menu links hierarchies.
  *
  * @group Menu
+ *
+ * @todo Move this under menu_link_content module.
+ *   https://www.drupal.org/node/2310353
  */
 class LinksTest extends WebTestBase {
 
@@ -22,7 +26,14 @@ class LinksTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('router_test');
+  public static $modules = array('router_test', 'menu_link_content');
+
+  /**
+   * The menu link plugin manager.
+   *
+   * @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
+   */
+  protected $menuLinkManager;
 
   /**
    * {@inheritdoc}
@@ -30,6 +41,8 @@ class LinksTest extends WebTestBase {
   public function setUp() {
     parent::setUp();
 
+    $this->menuLinkManager = \Drupal::service('plugin.manager.menu.link');
+
     entity_create('menu', array(
       'id' => 'menu_test',
       'label' => 'Test menu',
@@ -41,55 +54,60 @@ public function setUp() {
    * Create a simple hierarchy of links.
    */
   function createLinkHierarchy($module = 'menu_test') {
-    // First remove all the menu links.
-    $menu_links = menu_link_load_multiple();
-    menu_link_delete_multiple(array_keys($menu_links), TRUE, TRUE);
+    // First remove all the menu links in the menu.
+    $this->menuLinkManager->deleteLinksInMenu('menu_test');
 
     // Then create a simple link hierarchy:
-    // - $parent
-    //   - $child-1
-    //      - $child-1-1
-    //      - $child-1-2
-    //   - $child-2
+    // - parent
+    //   - child-1
+    //      - child-1-1
+    //      - child-1-2
+    //   - child-2
     $base_options = array(
-      'link_title' => 'Menu link test',
-      'module' => $module,
+      'title' => 'Menu link test',
+      'provider' => $module,
       'menu_name' => 'menu_test',
+      'bundle' => 'menu_link_content'
     );
 
-    $links['parent'] = $base_options + array(
-      'link_path' => 'menu-test/parent',
+    $parent = $base_options + array(
+      'route_name' => 'menu_test.hierarchy_parent',
     );
-    $links['parent'] = entity_create('menu_link', $links['parent']);
-    $links['parent']->save();
+    $link = entity_create('menu_link_content', $parent);
+    $link->save();
+    $links['parent'] = $link->getPluginId();
 
-    $links['child-1'] = $base_options + array(
-      'link_path' => 'menu-test/parent/child-1',
-      'plid' => $links['parent']['mlid'],
+    $child_1 = $base_options + array(
+      'route_name' => 'menu_test.hierarchy_parent_child',
+      'parent' => $links['parent'],
     );
-    $links['child-1'] = entity_create('menu_link', $links['child-1']);
-    $links['child-1']->save();
+    $link = entity_create('menu_link_content', $child_1);
+    $link->save();
+    $links['child-1'] = $link->getPluginId();
 
-    $links['child-1-1'] = $base_options + array(
-      'link_path' => 'menu-test/parent/child-1/child-1-1',
-      'plid' => $links['child-1']['mlid'],
+    $child_1_1 = $base_options + array(
+      'route_name' => 'menu_test.hierarchy_parent_child2',
+      'parent' => $links['child-1'],
     );
-    $links['child-1-1'] = entity_create('menu_link', $links['child-1-1']);
-    $links['child-1-1']->save();
+    $link = entity_create('menu_link_content', $child_1_1);
+    $link->save();
+    $links['child-1-1'] = $link->getPluginId();
 
-    $links['child-1-2'] = $base_options + array(
-      'link_path' => 'menu-test/parent/child-1/child-1-2',
-      'plid' => $links['child-1']['mlid'],
+    $child_1_2 = $base_options + array(
+      'route_name' => 'menu_test.hierarchy_parent_child2',
+      'parent' => $links['child-1'],
     );
-    $links['child-1-2'] = entity_create('menu_link', $links['child-1-2']);
-    $links['child-1-2']->save();
+    $link = entity_create('menu_link_content', $child_1_2);
+    $link->save();
+    $links['child-1-2'] = $link->getPluginId();
 
-    $links['child-2'] = $base_options + array(
-      'link_path' => 'menu-test/parent/child-2',
-      'plid' => $links['parent']['mlid'],
+    $child_2 = $base_options + array(
+      'route_name' => 'menu_test.hierarchy_parent_child',
+      'parent' => $links['parent'],
     );
-    $links['child-2'] = entity_create('menu_link', $links['child-2']);
-    $links['child-2']->save();
+    $link = entity_create('menu_link_content', $child_2);
+    $link->save();
+    $links['child-2'] = $link->getPluginId();
 
     return $links;
   }
@@ -98,13 +116,12 @@ function createLinkHierarchy($module = 'menu_test') {
    * Assert that at set of links is properly parented.
    */
   function assertMenuLinkParents($links, $expected_hierarchy) {
-    foreach ($expected_hierarchy as $child => $parent) {
-      $mlid = $links[$child]['mlid'];
-      $plid = $parent ? $links[$parent]['mlid'] : 0;
+    foreach ($expected_hierarchy as $id => $parent) {
+      /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin  */
+      $menu_link_plugin = $this->menuLinkManager->createInstance($links[$id]);
+      $expected_parent = isset($links[$parent]) ? $links[$parent] : '';
 
-      $menu_link = menu_link_load($mlid);
-      menu_link_save($menu_link);
-      $this->assertEqual($menu_link['plid'], $plid, format_string('Menu link %mlid has parent of %plid, expected %expected_plid.', array('%mlid' => $mlid, '%plid' => $menu_link['plid'], '%expected_plid' => $plid)));
+      $this->assertEqual($menu_link_plugin->getParent(), $expected_parent, String::format('Menu link %id has parent of %parent, expected %expected_parent.', array('%id' => $id, '%parent' => $menu_link_plugin->getParent(), '%expected_parent' => $expected_parent)));
     }
   }
 
@@ -116,7 +133,7 @@ function testMenuLinkReparenting($module = 'menu_test') {
     $links = $this->createLinkHierarchy($module);
 
     $expected_hierarchy = array(
-      'parent' => FALSE,
+      'parent' => '',
       'child-1' => 'parent',
       'child-1-1' => 'child-1',
       'child-1-2' => 'child-1',
@@ -127,11 +144,15 @@ function testMenuLinkReparenting($module = 'menu_test') {
     // Start over, and move child-1 under child-2, and check that all the
     // childs of child-1 have been moved too.
     $links = $this->createLinkHierarchy($module);
-    $links['child-1']['plid'] = $links['child-2']['mlid'];
-    menu_link_save($links['child-1']);
+    /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin  */
+    $this->menuLinkManager->updateDefinition($links['child-1'], array('parent' => $links['child-2']));
+    // Verify that the entity was updated too.
+    $menu_link_plugin = $this->menuLinkManager->createInstance($links['child-1']);
+    $entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $menu_link_plugin->getDerivativeId());
+    $this->assertEqual($entity->getParentId(), $links['child-2']);
 
     $expected_hierarchy = array(
-      'parent' => FALSE,
+      'parent' => '',
       'child-1' => 'child-2',
       'child-1-1' => 'child-1',
       'child-1-2' => 'child-1',
@@ -140,29 +161,9 @@ function testMenuLinkReparenting($module = 'menu_test') {
     $this->assertMenuLinkParents($links, $expected_hierarchy);
 
     // Start over, and delete child-1, and check that the children of child-1
-    // have been reassigned to the parent. menu_link_delete() will cowardly
-    // refuse to delete a menu link defined by the system module, so skip the
-    // test in that case.
-    if ($module != 'system') {
-      $links = $this->createLinkHierarchy($module);
-      menu_link_delete($links['child-1']['mlid']);
-
-      $expected_hierarchy = array(
-        'parent' => FALSE,
-        'child-1-1' => 'parent',
-        'child-1-2' => 'parent',
-        'child-2' => 'parent',
-      );
-      $this->assertMenuLinkParents($links, $expected_hierarchy);
-    }
-
-    // Start over, forcefully delete child-1 from the database, simulating a
-    // database crash. Check that the children of child-1 have been reassigned
-    // to the parent, going up on the old path hierarchy stored in each of the
-    // links.
+    // have been reassigned to the parent.
     $links = $this->createLinkHierarchy($module);
-    // Don't do that at home.
-    entity_delete_multiple('menu_link', array($links['child-1']['mlid']));
+    $this->menuLinkManager->removeDefinition($links['child-1']);
 
     $expected_hierarchy = array(
       'parent' => FALSE,
@@ -172,119 +173,26 @@ function testMenuLinkReparenting($module = 'menu_test') {
     );
     $this->assertMenuLinkParents($links, $expected_hierarchy);
 
-    // Start over, forcefully delete the parent from the database, simulating a
-    // database crash. Check that the children of parent are now top-level.
-    $links = $this->createLinkHierarchy($module);
-    // Don't do that at home.
-    db_delete('menu_links')
-      ->condition('mlid', $links['parent']['mlid'])
-      ->execute();
-
-    $expected_hierarchy = array(
-      'child-1-1' => 'child-1',
-      'child-1-2' => 'child-1',
-      'child-2' => FALSE,
-    );
-    $this->assertMenuLinkParents($links, $expected_hierarchy);
-  }
-
-  /**
-   * Tests automatic reparenting.
-   *
-   * Runs tests on menu links defined by the menu_link.static service.
-   */
-  function testMenuLinkRouterReparenting() {
-    // Run all the standard parenting tests on menu links derived from
-    // menu routers.
-    $this->testMenuLinkReparenting('system');
-
-    // Additionnaly, test reparenting based on path.
-    $links = $this->createLinkHierarchy('system');
-
-    // Move child-1-2 has a child of child-2, making the link hierarchy
-    // inconsistent with the path hierarchy.
-    $links['child-1-2']['plid'] = $links['child-2']['mlid'];
-    menu_link_save($links['child-1-2']);
-
-    // Check the new hierarchy.
-    $expected_hierarchy = array(
-      'parent' => FALSE,
-      'child-1' => 'parent',
-      'child-1-1' => 'child-1',
-      'child-2' => 'parent',
-      'child-1-2' => 'child-2',
-    );
-    $this->assertMenuLinkParents($links, $expected_hierarchy);
-
-    // Now delete 'parent' directly from the database, simulating a database
-    // crash. 'child-1' and 'child-2' should get moved to the
-    // top-level.
-    // Don't do that at home.
-    db_delete('menu_links')
-      ->condition('mlid', $links['parent']['mlid'])
-      ->execute();
-    $expected_hierarchy = array(
-      'child-1' => FALSE,
-      'child-1-1' => 'child-1',
-      'child-2' => FALSE,
-      'child-1-2' => 'child-2',
-    );
-    $this->assertMenuLinkParents($links, $expected_hierarchy);
-
-    // Now delete 'child-2' directly from the database, simulating a database
-    // crash. 'child-1-2' will get reparented to the top.
-    // Don't do that at home.
-    db_delete('menu_links')
-      ->condition('mlid', $links['child-2']['mlid'])
-      ->execute();
-    $expected_hierarchy = array(
-      'child-1' => FALSE,
-      'child-1-1' => 'child-1',
-      'child-1-2' => FALSE,
-    );
-    $this->assertMenuLinkParents($links, $expected_hierarchy);
-  }
-
-  /**
-   * Tests the router system integration (route_name and route_parameters).
-   */
-  public function testRouterIntegration() {
-    $menu_link = entity_create('menu_link', array(
-      'link_path' => 'router_test/test1',
-    ));
-    $menu_link->save();
-    $this->assertEqual($menu_link->route_name, 'router_test.1');
-    $this->assertEqual($menu_link->route_parameters, array());
-
-    $menu_link = entity_create('menu_link', array(
-      'link_path' => 'router_test/test3/test',
-    ));
-    $menu_link->save();
-    $this->assertEqual($menu_link->route_name, 'router_test.3');
-    $this->assertEqual($menu_link->route_parameters, array('value' => 'test'));
-
-    $menu_link = entity_load('menu_link', $menu_link->id());
-    $this->assertEqual($menu_link->route_name, 'router_test.3');
-    $this->assertEqual($menu_link->route_parameters, array('value' => 'test'));
+    // @todo Figure out what makes sense to test in terms of automatic
+    //   re-parenting. https://www.drupal.org/node/2309531
   }
 
   /**
-   * Tests uninstall a module providing default links.
+   * Tests uninstalling a module providing default links.
    */
   public function testModuleUninstalledMenuLinks() {
     \Drupal::moduleHandler()->install(array('menu_test'));
     \Drupal::service('router.builder')->rebuild();
-    menu_link_rebuild_defaults();
-    $result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
-    $menu_links = \Drupal::entityManager()->getStorage('menu_link')->loadMultiple($result);
+    \Drupal::service('plugin.manager.menu.link')->rebuild();
+    $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
     $this->assertEqual(count($menu_links), 1);
     $menu_link = reset($menu_links);
-    $this->assertEqual($menu_link->machine_name, 'menu_test');
+    $this->assertEqual($menu_link->getPluginId(), 'menu_test');
 
     // Uninstall the module and ensure the menu link got removed.
     \Drupal::moduleHandler()->uninstall(array('menu_test'));
-    $result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
-    $menu_links = \Drupal::entityManager()->getStorage('menu_link')->loadMultiple($result);
+    \Drupal::service('plugin.manager.menu.link')->rebuild();
+    $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
     $this->assertEqual(count($menu_links), 0);
   }
 
diff --git a/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php b/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php
new file mode 100644
index 0000000..6078875
--- /dev/null
+++ b/core/modules/system/src/Tests/Menu/MenuLinkDefaultIntegrationTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Menu\MenuLinkDefaultIntegrationTest.
+ */
+
+namespace Drupal\system\Tests\Menu;
+
+use Drupal\Core\Menu\MenuTreeParameters;
+use Drupal\simpletest\KernelTestBase;
+
+/**
+ * Tests integration of static menu links.
+ *
+ * @group Menu
+ */
+class MenuLinkDefaultIntegrationTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array(
+    'system',
+    'menu_test',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', array('router'));
+  }
+
+  /**
+   * Tests moving a static menu link without a specified menu to the root.
+   */
+  public function testMoveToRoot() {
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $menu_link_manager->rebuild();
+
+    $menu_link = $menu_link_manager->getDefinition('menu_test.child');
+    $this->assertEqual($menu_link['parent'], 'menu_test.parent');
+    $this->assertEqual($menu_link['menu_name'], 'test');
+
+    $tree = \Drupal::menuTree()->load('test', new MenuTreeParameters());
+    $this->assertEqual(count($tree), 1);
+    $this->assertEqual($tree['menu_test.parent']->link->getPluginId(), 'menu_test.parent');
+    $this->assertEqual($tree['menu_test.parent']->subtree['menu_test.child']->link->getPluginId(), 'menu_test.child');
+
+    // Ensure that the menu name is not forgotten.
+    $menu_link_manager->updateDefinition('menu_test.child', array('parent' => ''));
+    $menu_link = $menu_link_manager->getDefinition('menu_test.child');
+
+    $this->assertEqual($menu_link['parent'], '');
+    $this->assertEqual($menu_link['menu_name'], 'test');
+
+    $tree = \Drupal::menuTree()->load('test', new MenuTreeParameters());
+    $this->assertEqual(count($tree), 2);
+    $this->assertEqual($tree['menu_test.parent']->link->getPluginId(), 'menu_test.parent');
+    $this->assertEqual($tree['menu_test.child']->link->getPluginId(), 'menu_test.child');
+
+    $this->assertTrue(TRUE);
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
index 1b97c98..98b9685 100644
--- a/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuLinkTreeTest.php
@@ -43,7 +43,6 @@ class MenuLinkTreeTest extends KernelTestBase {
   public static $modules = array(
     'system',
     'menu_test',
-    'menu_link',
     'menu_link_content',
     'field',
   );
diff --git a/core/modules/system/src/Tests/Menu/MenuRouterRebuildTest.php b/core/modules/system/src/Tests/Menu/MenuRouterRebuildTest.php
deleted file mode 100644
index e56796f..0000000
--- a/core/modules/system/src/Tests/Menu/MenuRouterRebuildTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\Tests\Menu\MenuRouterRebuildTest.
- */
-
-namespace Drupal\system\Tests\Menu;
-
-use Drupal\simpletest\WebTestBase;
-use Drupal\Core\Language\Language;
-
-/**
- * Tests menu_router_rebuild().
- *
- * @group Menu
- */
-class MenuRouterRebuildTest extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('language', 'menu_test');
-
-  /**
-   * {@inheritdoc}
-   */
-  function setUp() {
-    parent::setUp();
-
-    $language = new Language(array('id' => 'nl'));
-    language_save($language);
-  }
-
-  /**
-   * Tests configuration context when rebuilding the menu router table.
-   */
-  public function testMenuRouterRebuildContext() {
-    // Enter a language context before rebuilding the menu router tables.
-    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('nl'));
-    \Drupal::service('router.builder')->rebuild();
-
-    // Check that the language context was not used for building the menu item.
-    $menu_items = \Drupal::entityManager()->getStorage('menu_link')->loadByProperties(array('route_name' => 'menu_test.context'));
-    $menu_item = reset($menu_items);
-    $this->assertTrue($menu_item['link_title'] == 'English', 'Config context overrides are ignored when rebuilding menu router items.');
-  }
-
-}
diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
index 26a0beb..270badc 100644
--- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
@@ -52,11 +52,7 @@ public function testMenuIntegration() {
     $this->doTestMenuOptionalPlaceholders();
     $this->doTestMenuOnRoute();
     $this->doTestMenuName();
-    $this->doTestMenuLinkDefaultsAlter();
-    $this->doTestMenuItemTitlesCases();
-    $this->doTestMenuLinkMaintain();
-    $this->doTestMenuLinkOptions();
-    $this->doTestMenuItemHooks();
+    $this->doTestMenuLinksDiscoveredAlter();
     $this->doTestHookMenuIntegration();
     $this->doTestExoticPath();
   }
@@ -109,182 +105,60 @@ protected function doTestDescriptionMenuItems() {
   }
 
   /**
-   * Tests for menu_link_maintain().
-   */
-  protected function doTestMenuLinkMaintain() {
-    $admin_user = $this->drupalCreateUser(array('administer site configuration'));
-    $this->drupalLogin($admin_user);
-
-    // Create three menu items.
-    menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1');
-    menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-main');
-    menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/2', 'Menu link #2');
-
-    // Move second link to the main-menu, to test caching later on.
-    $menu_links_to_update = entity_load_multiple_by_properties('menu_link', array('link_title' => 'Menu link #1-main', 'customized' => 0, 'module' => 'menu_test'));
-    foreach ($menu_links_to_update as $menu_link) {
-      $menu_link->menu_name = 'main';
-      $menu_link->save();
-    }
-
-    // Load front page.
-    $this->drupalGet('');
-    $this->assertLink('Menu link #1');
-    $this->assertLink('Menu link #1-main');
-    $this->assertLink('Menu link #2');
-
-    // Rename all links for the given path.
-    menu_link_maintain('menu_test', 'update', 'menu_test_maintain/1', 'Menu link updated');
-    // Load a different page to be sure that we have up to date information.
-    $this->drupalGet('menu_test_maintain/1');
-    $this->assertLink('Menu link updated');
-    $this->assertNoLink('Menu link #1');
-    $this->assertNoLink('Menu link #1-main');
-    $this->assertLink('Menu link #2');
-
-    // Delete all links for the given path.
-    menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/1', '');
-    // Load a different page to be sure that we have up to date information.
-    $this->drupalGet('menu_test_maintain/2');
-    $this->assertNoLink('Menu link updated');
-    $this->assertNoLink('Menu link #1');
-    $this->assertNoLink('Menu link #1-main');
-    $this->assertLink('Menu link #2');
-  }
-
-  /**
    * Tests for menu_name parameter for default menu links.
    */
   protected function doTestMenuName() {
     $admin_user = $this->drupalCreateUser(array('administer site configuration'));
     $this->drupalLogin($admin_user);
-
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu_name_test'));
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.menu_name_test');
     $menu_link = reset($menu_links);
-    $this->assertEqual($menu_link->menu_name, 'original', 'Menu name is "original".');
+    $this->assertEqual($menu_link->getMenuName(), 'original', 'Menu name is "original".');
 
     // Change the menu_name parameter in menu_test.module, then force a menu
     // rebuild.
     menu_test_menu_name('changed');
-    \Drupal::service('router.builder')->rebuild();
+    $menu_link_manager->rebuild();
 
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu_name_test'));
+    $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.menu_name_test');
     $menu_link = reset($menu_links);
-    $this->assertEqual($menu_link->menu_name, 'changed', 'Menu name was successfully changed after rebuild.');
+    $this->assertEqual($menu_link->getMenuName(), 'changed', 'Menu name was successfully changed after rebuild.');
   }
 
   /**
-   * Tests menu links added in hook_menu_link_defaults_alter().
+   * Tests menu links added in hook_menu_links_discovered_alter().
    */
-  protected function doTestMenuLinkDefaultsAlter() {
+  protected function doTestMenuLinksDiscoveredAlter() {
     // Check that machine name does not need to be defined since it is already
     // set as the key of each menu link.
-    $menu_links = entity_load_multiple_by_properties('menu_link', array('route_name' => 'menu_test.custom'));
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.custom');
     $menu_link = reset($menu_links);
-    $this->assertEqual($menu_link->machine_name, 'menu_test.custom', 'Menu links added at hook_menu_link_defaults_alter() obtain the machine name from the $links key.');
+    $this->assertEqual($menu_link->getPluginId(), 'menu_test.custom', 'Menu links added at hook_menu_links_discovered_alter() obtain the machine name from the $links key.');
     // Make sure that rebuilding the menu tree does not produce duplicates of
-    // links added by hook_menu_link_defaults_alter().
+    // links added by hook_menu_links_discovered_alter().
     \Drupal::service('router.builder')->rebuild();
     $this->drupalGet('menu-test');
-    $this->assertUniqueText('Custom link', 'Menu links added by hook_menu_link_defaults_alter() do not duplicate after a menu rebuild.');
+    $this->assertUniqueText('Custom link', 'Menu links added by hook_menu_links_discovered_alter() do not duplicate after a menu rebuild.');
   }
 
   /**
    * Tests for menu hierarchy.
    */
   protected function doTestMenuHierarchy() {
-    $parent_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent'));
-    $parent_link = reset($parent_links);
-    $child_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent/child'));
-    $child_link = reset($child_links);
-    $unattached_child_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent/child2/child'));
-    $unattached_child_link = reset($unattached_child_links);
-
-    $this->assertEqual($child_link['plid'], $parent_link['mlid'], 'The parent of a directly attached child is correct.');
-    $this->assertEqual($unattached_child_link['plid'], $parent_link['mlid'], 'The parent of a non-directly attached child is correct.');
-  }
-
-  /**
-   * Test menu maintenance hooks.
-   */
-  protected function doTestMenuItemHooks() {
-    // Create an item.
-    menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/4', 'Menu link #4');
-    $this->assertEqual(menu_test_static_variable(), 'insert', 'hook_menu_link_insert() fired correctly');
-    // Update the item.
-    menu_link_maintain('menu_test', 'update', 'menu_test_maintain/4', 'Menu link updated');
-    $this->assertEqual(menu_test_static_variable(), 'update', 'hook_menu_link_update() fired correctly');
-    // Delete the item.
-    menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/4', '');
-    $this->assertEqual(menu_test_static_variable(), 'delete', 'hook_menu_link_delete() fired correctly');
-  }
-
-  /**
-   * Test menu link 'options' storage and rendering.
-   */
-  protected function doTestMenuLinkOptions() {
-    // Create a menu link with options.
-    $menu_link = entity_create('menu_link', array(
-      'link_title' => 'Menu link options test',
-      'link_path' => 'test-page',
-      'module' => 'menu_test',
-      'options' => array(
-        'attributes' => array(
-          'title' => 'Test title attribute',
-        ),
-        'query' => array(
-          'testparam' => 'testvalue',
-        ),
-      ),
-    ));
-    menu_link_save($menu_link);
-
-    // Load front page.
-    $this->drupalGet('test-page');
-    $this->assertRaw('title="Test title attribute"', 'Title attribute of a menu link renders.');
-    $this->assertRaw('testparam=testvalue', 'Query parameter added to menu link.');
-  }
-
-  /**
-   * Tests the possible ways to set the title for menu items.
-   * Also tests that menu item titles work with string overrides.
-   */
-  protected function doTestMenuItemTitlesCases() {
-
-    // Build array with string overrides.
-    $test_data = array(
-      1 => array('Example title - Case 1' => 'Alternative example title - Case 1'),
-      2 => array('Example title' => 'Alternative example title'),
-      3 => array('Example title' => 'Alternative example title'),
-    );
-
-    foreach ($test_data as $case_no => $override) {
-      $this->menuItemTitlesCasesHelper($case_no);
-      $this->addCustomTranslations('en', array('' => $override));
-      $this->writeCustomTranslations();
-
-      $this->menuItemTitlesCasesHelper($case_no, TRUE);
-      $this->addCustomTranslations('en', array());
-      $this->writeCustomTranslations();
-    }
-  }
-
-  /**
-   * Get a URL and assert the title given a case number. If override is true,
-   * the title is asserted to begin with "Alternative".
-   */
-  protected function menuItemTitlesCasesHelper($case_no, $override = FALSE) {
-    $this->drupalGet('menu-title-test/case' . $case_no);
-    $this->assertResponse(200);
-    $asserted_title = $override ? 'Alternative example title - Case ' . $case_no : 'Example title - Case ' . $case_no;
-    $this->assertTitle($asserted_title . ' | Drupal', format_string('Menu title is: %title.', array('%title' => $asserted_title)), 'Menu');
-  }
-
-  /**
-   * Load the router for a given path.
-   */
-  protected function menuLoadRouter($router_path) {
-    return db_query('SELECT * FROM {menu_router} WHERE path = :path', array(':path' => $router_path))->fetchAssoc();
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent');
+    $parent_link = reset($menu_links);
+    $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent.child');
+    $child_link = reset($menu_links);
+    $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent.child2.child');
+    $unattached_child_link = reset($menu_links);
+
+    $this->assertEqual($child_link->getParent(), $parent_link->getPluginId(), 'The parent of a directly attached child is correct.');
+    $this->assertEqual($unattached_child_link->getParent(), $parent_link->getPluginId(), 'The parent of a non-directly attached child is correct.');
   }
 
   /**
diff --git a/core/modules/system/src/Tests/System/AdminTest.php b/core/modules/system/src/Tests/System/AdminTest.php
index 950194f..f5609c7 100644
--- a/core/modules/system/src/Tests/System/AdminTest.php
+++ b/core/modules/system/src/Tests/System/AdminTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\System;
 
+use Drupal\Core\Menu\MenuTreeParameters;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -62,9 +63,10 @@ function testAdminPages() {
     // Verify that all visible, top-level administration links are listed on
     // the main administration page.
     foreach ($this->getTopLevelMenuLinks() as $item) {
-      $this->assertLink($item['title']);
-      $this->assertLinkByHref($item['link_path']);
-      $this->assertText($item['localized_options']['attributes']['title']);
+      $this->assertLink($item->getTitle());
+      $this->assertLinkByHref($item->getUrlObject()->toString());
+      // The description should appear below the link.
+      $this->assertText($item->getDescription());
     }
 
     // For each administrative listing page on which the Locale module appears,
@@ -119,26 +121,28 @@ function testAdminPages() {
   /**
    * Returns all top level menu links.
    *
-   * @return \Drupal\menu_link\MenuLinkInterface[]
+   * @return \Drupal\Core\Menu\MenuLinkInterface[]
    */
   protected function getTopLevelMenuLinks() {
-    $route_provider = \Drupal::service('router.route_provider');
-    $routes = array();
-    foreach ($route_provider->getAllRoutes() as $key => $value) {
-      $path = $value->getPath();
-      if (strpos($path, '/admin/') === 0 && count(explode('/', $path)) == 3) {
-        $routes[$key] = $key;
-      }
-    }
-    $menu_link_ids = \Drupal::entityQuery('menu_link')
-      ->condition('route_name', $routes)
-      ->execute();
+    $menu_tree = \Drupal::menuTree();
+
+    // The system.admin link is normally the parent of all top-level admin links.
+    $parameters = new MenuTreeParameters();
+    $parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
+    $tree = $menu_tree->load(NULL, $parameters);
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+      array('callable' => 'menu.default_tree_manipulators:flatten'),
+    );
+    $tree = $menu_tree->transform($tree, $manipulators);
 
-    $menu_items = \Drupal::entityManager()->getStorage('menu_link')->loadMultiple($menu_link_ids);
-    foreach ($menu_items as &$menu_item) {
-      _menu_link_translate($menu_item);
+    // Transform the tree to a list of menu links.
+    $menu_links = array();
+    foreach ($tree as $element) {
+      $menu_links[] = $element->link;
     }
-    return $menu_items;
+
+    return $menu_links;
   }
 
   /**
diff --git a/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php b/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php
index b923daf..cabd863 100644
--- a/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php
+++ b/core/modules/system/src/Tests/System/SystemConfigFormTestBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\System;
 
+use Drupal\Core\Form\FormState;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -47,11 +48,12 @@
    */
   public function testConfigForm() {
     // Programmatically submit the given values.
+    $values = array();
     foreach ($this->values as $form_key => $data) {
       $values[$form_key] = $data['#value'];
     }
-    $form_state = array('values' => $values);
-    drupal_form_submit($this->form, $form_state);
+    $form_state = new FormState(array('values' => $values));
+    \Drupal::formBuilder()->submitForm($this->form, $form_state);
 
     // Check that the form returns an error when expected, and vice versa.
     $errors = form_get_errors($form_state);
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 71b0cec..1fa53e8 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -59,7 +59,7 @@ function template_preprocess_admin_block_content(&$variables) {
       $variables['attributes']['class'][] = 'compact';
     }
     foreach ($variables['content'] as $key => $item) {
-      $variables['content'][$key]['link'] = l($item['title'], $item['link_path'], $item['localized_options']);
+      $variables['content'][$key]['link'] = \Drupal::linkGenerator()->generateFromUrl($item['title'], $item['url']);
       if (!$compact && isset($item['description'])) {
         $variables['content'][$key]['description'] = Xss::filterAdmin($item['description']);
       }
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 111ddfe..ee83508 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -397,13 +397,13 @@ function hook_page_build(&$page) {
 }
 
 /**
- * Alter links for menus.
+ * Alters all the menu links discovered by the menu link plugin manager.
  *
  * @param array $links
  *   The link definitions to be altered.
  *
  * @return array
- *   An array of default menu links. Each link has a key that is the machine
+ *   An array of discovered menu links. Each link has a key that is the machine
  *   name, which must be unique. By default, use the route name as the
  *   machine name. In cases where multiple links use the same route name, such
  *   as two links to the same page in different menus, or two links using the
@@ -440,7 +440,7 @@ function hook_page_build(&$page) {
  *
  * @ingroup menu
  */
-function hook_menu_link_defaults_alter(&$links) {
+function hook_menu_links_discovered_alter(&$links) {
   // Change the weight and title of the user.logout link.
   $links['user.logout']['weight'] = -10;
   $links['user.logout']['title'] = 'Logout';
@@ -692,9 +692,9 @@ function hook_page_alter(&$page) {
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
- *   A keyed array containing the current state of the form. The arguments
- *   that \Drupal::formBuilder()->getForm() was originally called with are
- *   available in the array $form_state['build_info']['args'].
+ *   The current state of the form. The arguments that
+ *   \Drupal::formBuilder()->getForm() was originally called with are available
+ *   in the array $form_state['build_info']['args'].
  * @param $form_id
  *   String representing the name of the form itself. Typically this is the
  *   name of the function that generated the form.
@@ -703,7 +703,7 @@ function hook_page_alter(&$page) {
  * @see hook_form_FORM_ID_alter()
  * @see forms_api_reference.html
  */
-function hook_form_alter(&$form, &$form_state, $form_id) {
+function hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
   if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
     $upload_enabled_types = \Drupal::config('mymodule.settings')->get('upload_enabled_types');
     $form['workflow']['upload_' . $form['type']['#value']] = array(
@@ -731,9 +731,9 @@ function hook_form_alter(&$form, &$form_state, $form_id) {
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
- *   A keyed array containing the current state of the form. The arguments
- *   that \Drupal::formBuilder()->getForm() was originally called with are
- *   available in the array $form_state['build_info']['args'].
+ *   The current state of the form. The arguments that
+ *   \Drupal::formBuilder()->getForm() was originally called with are available
+ *   in the array $form_state['build_info']['args'].
  * @param $form_id
  *   String representing the name of the form itself. Typically this is the
  *   name of the function that generated the form.
@@ -743,7 +743,7 @@ function hook_form_alter(&$form, &$form_state, $form_id) {
  * @see \Drupal\Core\Form\FormBuilderInterface::prepareForm()
  * @see forms_api_reference.html
  */
-function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
+function hook_form_FORM_ID_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
   // Modification for the form with the given form ID goes here. For example, if
   // FORM_ID is "user_register_form" this code would run only on the user
   // registration form.
@@ -779,7 +779,7 @@ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
- *   A keyed array containing the current state of the form.
+ *   The current state of the form.
  * @param $form_id
  *   String representing the name of the form itself. Typically this is the
  *   name of the function that generated the form.
@@ -788,7 +788,7 @@ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * @see hook_form_FORM_ID_alter()
  * @see \Drupal\Core\Form\FormBuilderInterface::prepareForm()
  */
-function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
+function hook_form_BASE_FORM_ID_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
   // Modification for the form with the given BASE_FORM_ID goes here. For
   // example, if BASE_FORM_ID is "node_form", this code would run on every
   // node form, regardless of node type.
@@ -2866,6 +2866,19 @@ function hook_config_import_steps_alter(&$sync_steps, \Drupal\Core\Config\Config
  * Note that you must use double quotes; single quotes will not work in
  * annotations.
  *
+ * Some annotation types, which extend the "@ PluginID" annotation class, have
+ * only a single 'id' key in their annotation. For these, it is possible to use
+ * a shorthand annotation. For example:
+ * @code
+ * * @ViewsArea("entity")
+ * @endcode
+ * in place of
+ * @code
+ * * @ViewsArea(
+ * *   id = "entity"
+ * *)
+ * @endcode
+ *
  * The available annotation classes are listed in this topic, and can be
  * identified when you are looking at the Drupal source code by having
  * "@ Annotation" in their documentation blocks (without the space after @). To
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index fc2c63f..f421e6b 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -8,9 +8,11 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\StringTranslation\TranslationWrapper;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Menu\MenuTreeParameters;
 use Drupal\block\BlockPluginInterface;
 use Drupal\user\UserInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -990,7 +992,7 @@ function system_page_build(&$page) {
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function system_form_user_form_alter(&$form, &$form_state) {
+function system_form_user_form_alter(&$form, FormStateInterface $form_state) {
   if (\Drupal::config('system.date')->get('timezone.user.configurable')) {
     system_user_timezone($form, $form_state);
   }
@@ -999,7 +1001,7 @@ function system_form_user_form_alter(&$form, &$form_state) {
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function system_form_user_register_form_alter(&$form, &$form_state) {
+function system_form_user_register_form_alter(&$form, FormStateInterface $form_state) {
   $config = \Drupal::config('system.date');
   if ($config->get('timezone.user.configurable') && $config->get('timezone.user.default') == DRUPAL_USER_TIMEZONE_SELECT) {
     system_user_timezone($form, $form_state);
@@ -1030,7 +1032,7 @@ function system_user_login($account) {
 /**
  * Add the time zone field to the user edit and register forms.
  */
-function system_user_timezone(&$form, &$form_state) {
+function system_user_timezone(&$form, FormStateInterface $form_state) {
   $user = \Drupal::currentUser();
 
   $account = $form_state['controller']->getEntity();
@@ -1455,76 +1457,48 @@ function system_admin_compact_mode() {
  *   An array of task links.
  */
 function system_get_module_admin_tasks($module, array $info) {
-  $links = &drupal_static(__FUNCTION__);
-
-  if (!isset($links)) {
-    $links = array();
-    $menu_links = entity_get_controller('menu_link')->loadModuleAdminTasks();
-    foreach ($menu_links as $link) {
-      _menu_link_translate($link);
-      if ($link['access']) {
-        $links[$link['machine_name']] = $link;
-      }
-    }
+  $tree = &drupal_static(__FUNCTION__);
+
+  $menu_tree = \Drupal::menuTree();
+
+  if (!isset($tree)) {
+    $parameters = new MenuTreeParameters();
+    $parameters->setRoot('system.admin')->excludeRoot()->excludeHiddenLinks();
+    $tree = $menu_tree->load('system.admin', $parameters);
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+      array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+      array('callable' => 'menu.default_tree_manipulators:flatten'),
+    );
+    $tree = $menu_tree->transform($tree, $manipulators);
   }
 
   $admin_tasks = array();
-  $titles = array();
-  foreach ($links as $item) {
-    if ($item['module'] != $module) {
+  foreach ($tree as $element) {
+    $link = $element->link;
+    if ($link->getProvider() != $module) {
       continue;
     }
-    $machine_name = $item['machine_name'];
-    if (isset($links[$machine_name])) {
-      $task = $links[$machine_name];
-      // The link description, either derived from 'description' in the default
-      // menu link or customized via Menu UI module is used as title attribute.
-      if (!empty($task['localized_options']['attributes']['title'])) {
-        $task['description'] = $task['localized_options']['attributes']['title'];
-        unset($task['localized_options']['attributes']['title']);
-      }
-
-      // Check the admin tasks for duplicate names. If one is found,
-      // append the parent menu item's title to differentiate.
-      $duplicate_path = array_search($task['title'], $titles);
-      if ($duplicate_path !== FALSE) {
-        if ($parent = menu_link_load($task['plid'])) {
-          // Append the parent item's title to this task's title.
-          $task['title'] = t('@original_title (@parent_title)', array('@original_title' => $task['title'], '@parent_title' => $parent['title']));
-        }
-        if ($parent = menu_link_load($admin_tasks[$duplicate_path]['plid'])) {
-          // Append the parent item's title to the duplicated task's title.
-          // We use $links[$duplicate_path] in case there are triplicates.
-          $admin_tasks[$duplicate_path]['title'] = t('@original_title (@parent_title)', array('@original_title' => $links[$duplicate_path]['title'], '@parent_title' => $parent['title']));
-        }
-      }
-      else {
-        $titles[$machine_name] = $task['title'];
-      }
-
-      $admin_tasks[$machine_name] = $task;
-    }
+    $admin_tasks[] = array(
+      'title' => $link->getTitle(),
+      'description' => $link->getDescription(),
+      'url' => $link->getUrlObject(),
+    );
   }
 
   // Append link for permissions.
   if (\Drupal::moduleHandler()->implementsHook($module, 'permission')) {
     /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
     $access_manager = \Drupal::service('access_manager');
-    /** @var \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage */
-    $menu_link_storage = \Drupal::entityManager()
-      ->getStorage('menu_link');
     if ($access_manager->checkNamedRoute('user.admin_permissions', array(), \Drupal::currentUser())) {
-      $path = \Drupal::urlGenerator()
-        ->getPathFromRoute('user.admin_permissions');
-      $options = array();
-      $options['fragment'] = 'module-' . $module;
-      $menu_link = $menu_link_storage->create(array(
-        'route_name' => 'user.admin_permissions',
-        'link_path' => $path,
+      /** @var \Drupal\Core\Url $url */
+      $url = new \Drupal\Core\Url('user.admin_permissions');
+      $url->setOption('fragment', 'module-' . $module);
+      $admin_tasks["user.admin_permissions.$module"] = array(
         'title' => t('Configure @module permissions', array('@module' => $info['name'])),
-        'localized_options' => $options
-      ));
-      $admin_tasks["user.admin.people.permissions.$module"] = $menu_link;
+        'description' => '',
+        'url' => $url,
+      );
     }
   }
 
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 35e17f7..c22d93b 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -382,7 +382,7 @@ system.admin_config:
   path: '/admin/config'
   defaults:
     _content: '\Drupal\system\Controller\SystemController::overview'
-    path: 'admin/config'
+    link_id: 'system.admin_config'
     _title: 'Configuration'
   requirements:
     _permission: 'access administration pages'
@@ -414,7 +414,7 @@ system.admin_content:
   path: '/admin/content'
   defaults:
     _content: '\Drupal\system\Controller\SystemController::overview'
-    path: 'admin/content'
+    link_id: 'system.admin_content'
     _title: 'Content'
   requirements:
     _permission: 'access administration pages'
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 2b7046c..9e09d19 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -5,7 +5,7 @@ services:
       - { name: access_check, applies_to: _access_system_cron }
   system.manager:
     class: Drupal\system\SystemManager
-    arguments: ['@module_handler', '@database', '@entity.manager', '@request_stack']
+    arguments: ['@module_handler', '@database', '@entity.manager', '@request_stack', '@menu.link_tree', '@menu.active_trail']
   system.breadcrumb.default:
     class: Drupal\system\PathBasedBreadcrumbBuilder
     arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory',  '@title_resolver', '@current_user']
diff --git a/core/modules/system/templates/menu-tree.html.twig b/core/modules/system/templates/menu-tree.html.twig
new file mode 100644
index 0000000..03acca6
--- /dev/null
+++ b/core/modules/system/templates/menu-tree.html.twig
@@ -0,0 +1,40 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a menu tree.
+ *
+ * Available variables:
+ * - attributes: Attributes for the UL containing the tree of links.
+ * - tree: Menu tree to be output.
+ * - heading: (optional) A heading to precede the links.
+ *   - text: The heading text.
+ *   - level: The heading level (e.g. 'h2', 'h3').
+ *   - attributes: (optional) A keyed list of attributes for the heading.
+ *   If the heading is a string, it will be used as the text of the heading and
+ *   the level will default to 'h2'.
+ *
+ *   Headings should be used on navigation menus and any list of links that
+ *   consistently appears on multiple pages. To make the heading invisible use
+ *   the 'visually-hidden' CSS class. Do not use 'display:none', which
+ *   removes it from screen-readers and assistive technology. Headings allow
+ *   screen-reader and keyboard only users to navigate to or skip the links.
+ *   See http://juicystudio.com/article/screen-readers-display-none.php and
+ *   http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
+ *
+ * @see template_preprocess_menu_tree()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if tree -%}
+  {%- if heading -%}
+    {%- if heading.level -%}
+      <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}</{{ heading.level }}>
+    {%- else -%}
+      <h2{{ heading.attributes }}>{{ heading.text }}</h2>
+    {%- endif -%}
+  {%- endif -%}
+  <ul{{ attributes }}>
+    {{ tree }}
+  </ul>
+{%- endif %}
diff --git a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
index 3a605c5..8f8719a 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
+++ b/core/modules/system/tests/modules/ajax_forms_test/ajax_forms_test.module
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Ajax;
 use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Ajax form callback: Selects 'after'.
@@ -206,6 +207,6 @@ function ajax_forms_test_validation_number_form_callback($form, $form_state) {
 /**
  * AJAX form callback: Selects for the ajax_forms_test_lazy_load_form() form.
  */
-function ajax_forms_test_lazy_load_form_ajax($form, &$form_state) {
+function ajax_forms_test_lazy_load_form_ajax($form, FormStateInterface $form_state) {
   return array('#markup' => 'new content');
 }
diff --git a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestCommandsForm.php b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestCommandsForm.php
index 474b6ea..46525e7 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestCommandsForm.php
+++ b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestCommandsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\ajax_forms_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form constructor for the Ajax Command display form.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}.
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = array();
 
     // Shows the 'after' command with a callback generating commands.
@@ -216,7 +217,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}.
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestLazyLoadForm.php b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestLazyLoadForm.php
index d5761fe..762c306 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestLazyLoadForm.php
+++ b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestLazyLoadForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\ajax_forms_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder: Builds a form that triggers a simple AJAX callback.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // We attach a JavaScript setting, so that one of the generated AJAX
     // commands will be a settings command. We can then check the settings
     // command to ensure that the 'currentPath' setting is not part
@@ -54,7 +55,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['add_files']) {
       $path = drupal_get_path('module', 'system');
       $attached = array(
diff --git a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php
index a2a4cf8..225664d 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php
+++ b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestSimpleForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\ajax_forms_test\Callbacks;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder: Builds a form that triggers a simple AJAX callback.
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $object = new Callbacks();
 
     $form = array();
@@ -77,7 +78,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestValidationForm.php b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestValidationForm.php
index 3532279..bf7064e 100644
--- a/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestValidationForm.php
+++ b/core/modules/system/tests/modules/ajax_forms_test/src/Form/AjaxFormsTestValidationForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\ajax_forms_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder: Builds a form that triggers a simple AJAX callback.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['drivertext'] = array(
       '#title' => $this->t('AJAX-enabled textfield.'),
       '#description' => $this->t("When this one AJAX-triggers and the spare required field is empty, you should not get an error."),
@@ -68,7 +69,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t("Validation form submitted"));
   }
 
diff --git a/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestDialogForm.php b/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestDialogForm.php
index 9d598d8..5f11817 100644
--- a/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestDialogForm.php
+++ b/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestDialogForm.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\OpenModalDialogCommand;
 use Drupal\Core\Ajax\OpenDialogCommand;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Dummy form for testing DialogController with _form routes.
@@ -29,7 +30,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // In order to use WebTestBase::drupalPostAjaxForm() to POST from a link, we need
     // to have a dummy field we can set in WebTestBase::drupalPostForm() else it won't
     // submit anything.
@@ -59,14 +60,14 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
 
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['redirect'] = 'ajax-test/dialog-contents';
   }
 
@@ -74,14 +75,14 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * AJAX callback handler for AjaxTestDialogForm.
    */
-  public function modal(&$form, &$form_state) {
+  public function modal(&$form, FormStateInterface $form_state) {
     return $this->dialog(TRUE);
   }
 
   /**
    * AJAX callback handler for AjaxTestDialogForm.
    */
-  public function nonModal(&$form, &$form_state) {
+  public function nonModal(&$form, FormStateInterface $form_state) {
     return $this->dialog(FALSE);
   }
 
diff --git a/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php b/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php
index 462f671..4237316 100644
--- a/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php
+++ b/core/modules/system/tests/modules/ajax_test/src/Form/AjaxTestForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\ajax_test\Form;
 
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Dummy form for testing DialogController with _form routes.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
 
     $form['#action'] = url('ajax-test/dialog');
 
@@ -43,11 +44,11 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {}
+  public function submitForm(array &$form, FormStateInterface $form_state) {}
 
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {}
+  public function validateForm(array &$form, FormStateInterface $form_state) {}
 
 }
diff --git a/core/modules/system/tests/modules/batch_test/batch_test.module b/core/modules/system/tests/modules/batch_test/batch_test.module
index 5438acf..9290ef8 100644
--- a/core/modules/system/tests/modules/batch_test/batch_test.module
+++ b/core/modules/system/tests/modules/batch_test/batch_test.module
@@ -5,10 +5,13 @@
  * Helper module for the Batch API tests.
  */
 
+use Drupal\Core\Form\FormState;
+
 /**
  * Batch operation: Submits form_test_mock_form() using drupal_form_submit().
  */
 function _batch_test_nested_drupal_form_submit_callback($value) {
+  $state = new FormState();
   $state['values']['test_value'] = $value;
   \Drupal::formBuilder()->submitForm('Drupal\batch_test\Form\BatchTestMockForm', $state);
 }
diff --git a/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php b/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php
index 9afb0e9..fcd9b01 100644
--- a/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php
+++ b/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php
@@ -6,6 +6,7 @@
 
 namespace Drupal\batch_test\Controller;
 
+use Drupal\Core\Form\FormState;
 
 /**
  * Controller routines for batch tests.
@@ -84,9 +85,9 @@ public function testNoForm() {
    *   Render array containing markup.
    */
   function testProgrammatic($value = 1) {
-    $form_state = array(
+    $form_state = new FormState(array(
       'values' => array('value' => $value)
-    );
+    ));
     \Drupal::formBuilder()->submitForm('Drupal\batch_test\Form\BatchTestChainedForm', $form_state);
     return array(
       'success' => array(
diff --git a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestChainedForm.php b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestChainedForm.php
index c6603de..ae6430e 100644
--- a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestChainedForm.php
+++ b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestChainedForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\batch_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // This value is used to test that $form_state persists through batched
     // submit handlers.
     $form['value'] = array(
@@ -49,13 +50,13 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * Form submission handler #1 for batch_test_chained_form
    */
-  public static function batchTestChainedFormSubmit1($form, &$form_state) {
+  public static function batchTestChainedFormSubmit1($form, FormStateInterface $form_state) {
     batch_test_stack(NULL, TRUE);
 
     batch_test_stack('submit handler 1');
@@ -70,7 +71,7 @@ public static function batchTestChainedFormSubmit1($form, &$form_state) {
   /**
    * Form submission handler #2 for batch_test_chained_form
    */
-  public static function batchTestChainedFormSubmit2($form, &$form_state) {
+  public static function batchTestChainedFormSubmit2($form, FormStateInterface $form_state) {
     batch_test_stack('submit handler 2');
     batch_test_stack('value = ' . $form_state['values']['value']);
 
@@ -83,7 +84,7 @@ public static function batchTestChainedFormSubmit2($form, &$form_state) {
   /**
    * Form submission handler #3 for batch_test_chained_form
    */
-  public static function batchTestChainedFormSubmit3($form, &$form_state) {
+  public static function batchTestChainedFormSubmit3($form, FormStateInterface $form_state) {
     batch_test_stack('submit handler 3');
     batch_test_stack('value = ' . $form_state['values']['value']);
 
@@ -95,7 +96,7 @@ public static function batchTestChainedFormSubmit3($form, &$form_state) {
   /**
    * Form submission handler #4 for batch_test_chained_form
    */
-  public static function batchTestChainedFormSubmit4($form, &$form_state) {
+  public static function batchTestChainedFormSubmit4($form, FormStateInterface $form_state) {
     batch_test_stack('submit handler 4');
     batch_test_stack('value = ' . $form_state['values']['value']);
 
diff --git a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMockForm.php b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMockForm.php
index 6372c20..f72fc29 100644
--- a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMockForm.php
+++ b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMockForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\batch_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Generate form of id batch_test_mock_form.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['test_value'] = array(
       '#title' => t('Test value'),
       '#type' => 'textfield',
@@ -40,7 +41,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     batch_test_stack('mock form submitted with value = ' . $form_state['values']['test_value']);
   }
 
diff --git a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMultiStepForm.php b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMultiStepForm.php
index 4ce90a4..3743cac 100644
--- a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMultiStepForm.php
+++ b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestMultiStepForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\batch_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     if (empty($form_state['storage']['step'])) {
       $form_state['storage']['step'] = 1;
     }
@@ -44,7 +45,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     batch_test_stack(NULL, TRUE);
 
     switch ($form_state['storage']['step']) {
diff --git a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestSimpleForm.php b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestSimpleForm.php
index 3c39339..6bfa1c9 100644
--- a/core/modules/system/tests/modules/batch_test/src/Form/BatchTestSimpleForm.php
+++ b/core/modules/system/tests/modules/batch_test/src/Form/BatchTestSimpleForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\batch_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['batch'] = array(
       '#type' => 'select',
       '#title' => 'Choose batch',
@@ -48,7 +49,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     batch_test_stack(NULL, TRUE);
 
     $function = '_batch_test_' . $form_state['values']['batch'];
diff --git a/core/modules/system/tests/modules/condition_test/src/FormController.php b/core/modules/system/tests/modules/condition_test/src/FormController.php
index d713bb7..1f13755 100644
--- a/core/modules/system/tests/modules/condition_test/src/FormController.php
+++ b/core/modules/system/tests/modules/condition_test/src/FormController.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormInterface;
 use Drupal\Core\Condition\ConditionManager;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Routing controller class for condition_test testing of condition forms.
@@ -38,9 +39,9 @@ public function __construct() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = $this->condition->buildConfigurationForm($form, $form_state);
     $form['actions']['submit'] = array(
       '#type' => 'submit',
@@ -51,15 +52,16 @@ public function buildForm(array $form, array &$form_state) {
 
   /**
    * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   *
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $this->condition->validateConfigurationForm($form, $form_state);
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->condition->submitConfigurationForm($form, $form_state);
     $config = $this->condition->getConfig();
     $bundles = implode(' and ', $config['bundles']);
diff --git a/core/modules/system/tests/modules/database_test/src/Form/DatabaseTestForm.php b/core/modules/system/tests/modules/database_test/src/Form/DatabaseTestForm.php
index 12e7311..712ac97 100644
--- a/core/modules/system/tests/modules/database_test/src/Form/DatabaseTestForm.php
+++ b/core/modules/system/tests/modules/database_test/src/Form/DatabaseTestForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for database_test module.
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $header = array(
       'username' => array('data' => t('Username'), 'field' => 'u.name'),
       'status' => array('data' => t('Status'), 'field' => 'u.status'),
@@ -72,7 +73,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 864e302..6b293d1 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\entity\Entity\EntityFormDisplay;
 
@@ -242,7 +243,7 @@ function entity_test_permission() {
 /**
  * Implements hook_form_BASE_FORM_ID_alter().
  */
-function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) {
+function entity_test_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $langcode = $form_state['controller']->getFormLangcode($form_state);
   \Drupal::state()->set('entity_test.form_langcode', $langcode);
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php b/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php
index f9b0c4d..76fea69 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity_test;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -33,7 +34,7 @@ public function getQuestion() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
     $entity = $this->entity;
     $entity->delete();
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestForm.php b/core/modules/system/tests/modules/entity_test/src/EntityTestForm.php
index 2ca9d0d..ed56b50 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestForm.php
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestForm.php
@@ -7,6 +7,7 @@
 namespace Drupal\entity_test;
 
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
@@ -15,9 +16,9 @@
 class EntityTestForm extends ContentEntityForm {
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::form().
+   * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
     $entity = $this->entity;
 
@@ -61,9 +62,9 @@ public function form(array $form, array &$form_state) {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\EntityForm::submit().
+   * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // Build the entity object from the submitted values.
     $entity = parent::submit($form, $form_state);
 
@@ -76,9 +77,9 @@ public function submit(array $form, array &$form_state) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::save().
+   * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
     $is_new = $entity->isNew();
     $entity->save();
diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module
index 08fdb2e..ad38397 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -5,6 +5,8 @@
  * Helper module for the form API tests.
  */
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Implements hook_permission().
  */
@@ -23,14 +25,14 @@ function form_test_permission() {
 /**
  * Implements hook_form_FORM_ID_alter() on behalf of block.module.
  */
-function block_form_form_test_alter_form_alter(&$form, &$form_state) {
+function block_form_form_test_alter_form_alter(&$form, FormStateInterface $form_state) {
   drupal_set_message('block_form_form_test_alter_form_alter() executed.');
 }
 
 /**
  * Implements hook_form_alter().
  */
-function form_test_form_alter(&$form, &$form_state, $form_id) {
+function form_test_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   if ($form_id == 'form_test_alter_form') {
     drupal_set_message('form_test_form_alter() executed.');
   }
@@ -39,14 +41,14 @@ function form_test_form_alter(&$form, &$form_state, $form_id) {
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function form_test_form_form_test_alter_form_alter(&$form, &$form_state) {
+function form_test_form_form_test_alter_form_alter(&$form, FormStateInterface $form_state) {
   drupal_set_message('form_test_form_form_test_alter_form_alter() executed.');
 }
 
 /**
  * Implements hook_form_FORM_ID_alter() on behalf of system.module.
  */
-function system_form_form_test_alter_form_alter(&$form, &$form_state) {
+function system_form_form_test_alter_form_alter(&$form, FormStateInterface $form_state) {
   drupal_set_message('system_form_form_test_alter_form_alter() executed.');
 }
 
@@ -93,7 +95,7 @@ function _form_test_tableselect_get_data() {
  *
  * @see form_test_state_persist()
  */
-function form_test_form_form_test_state_persist_alter(&$form, &$form_state) {
+function form_test_form_form_test_state_persist_alter(&$form, FormStateInterface $form_state) {
   // Simulate a form alter implementation inserting form elements that enable
   // caching of the form, e.g. elements having #ajax.
   if (\Drupal::request()->get('cache')) {
@@ -104,7 +106,7 @@ function form_test_form_form_test_state_persist_alter(&$form, &$form_state) {
 /**
  * Implements hook_form_FORM_ID_alter() for the registration form.
  */
-function form_test_form_user_register_form_alter(&$form, &$form_state) {
+function form_test_form_user_register_form_alter(&$form, FormStateInterface $form_state) {
   $form['test_rebuild'] = array(
     '#type' => 'submit',
     '#value' => t('Rebuild'),
@@ -115,7 +117,7 @@ function form_test_form_user_register_form_alter(&$form, &$form_state) {
 /**
  * Submit callback that just lets the form rebuild.
  */
-function form_test_user_register_form_rebuild($form, &$form_state) {
+function form_test_user_register_form_rebuild($form, FormStateInterface $form_state) {
   drupal_set_message('Form rebuilt.');
   $form_state['rebuild'] = TRUE;
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Callbacks.php b/core/modules/system/tests/modules/form_test/src/Callbacks.php
index 08d970d..73fd437 100644
--- a/core/modules/system/tests/modules/form_test/src/Callbacks.php
+++ b/core/modules/system/tests/modules/form_test/src/Callbacks.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\form_test;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Simple class for testing methods as Form API callbacks.
  */
@@ -15,7 +17,7 @@ class Callbacks {
   /**
    * Form element validation handler for 'name' in form_test_validate_form().
    */
-  public function validateName(&$element, &$form_state) {
+  public function validateName(&$element, FormStateInterface $form_state) {
     $triggered = FALSE;
     if ($form_state['values']['name'] == 'element_validate') {
       // Alter the form element.
diff --git a/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php b/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php
index b1d69bc..d650455 100644
--- a/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php
+++ b/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test;
 
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -60,7 +61,7 @@ public function getCancelText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['element'] = array('#markup' => '<p>The ConfirmFormTestForm::buildForm() method was used for this form.</p>');
 
     return parent::buildForm($form, $form_state);
@@ -69,7 +70,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The ConfirmFormTestForm::submitForm() method was used for this form.'));
     $form_state['redirect_route']['route_name'] = '<front>';
   }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestAlterForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestAlterForm.php
index 3052d76..170e92b 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestAlterForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestAlterForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder for testing hook_form_alter() and hook_form_FORM_ID_alter().
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Elements can be added as needed for future testing needs, but for now,
     // we're only testing alter hooks that do not require any elements added by
     // this function.
@@ -34,7 +35,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestButtonClassForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestButtonClassForm.php
index 1110120..542a104 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestButtonClassForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestButtonClassForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form to test form button classes.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['button'] = array(
       '#type' => 'button',
       '#value' => 'test',
@@ -41,7 +42,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxForm.php
index 1ca9a16..6a23006 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 class FormTestCheckboxForm extends FormBase {
@@ -22,7 +23,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // A required checkbox.
     $form['required_checkbox'] = array(
       '#type' => 'checkbox',
@@ -90,7 +91,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxTypeJugglingForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxTypeJugglingForm.php
index 64a2206..335c1d7 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxTypeJugglingForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxTypeJugglingForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a form to test return values for checkboxes.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $default_value = NULL, $return_value = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $default_value = NULL, $return_value = NULL) {
     $form['checkbox'] = array(
       '#title' => t('Checkbox'),
       '#type' => 'checkbox',
@@ -37,7 +38,7 @@ public function buildForm(array $form, array &$form_state, $default_value = NULL
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesRadiosForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesRadiosForm.php
index 4b84cf1..721399e 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesRadiosForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesRadiosForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $customize = FALSE) {
+  public function buildForm(array $form, FormStateInterface $form_state, $customize = FALSE) {
     // Expand #type checkboxes, setting custom element properties for some but not
     // all options.
     $form['checkboxes'] = array(
@@ -82,7 +83,7 @@ public function buildForm(array $form, array &$form_state, $customize = FALSE) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesZeroForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesZeroForm.php
index 08356ad..709a76d 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesZeroForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestCheckboxesZeroForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $json = TRUE) {
+  public function buildForm(array $form, FormStateInterface $form_state, $json = TRUE) {
     $form_state['json'] = $json;
     $form['checkbox_off'] = array(
       '#title' => t('Checkbox off'),
@@ -54,7 +55,7 @@ public function buildForm(array $form, array &$form_state, $json = TRUE) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if (!empty($form_state['json'])) {
       $form_state['response'] = new JsonResponse($form_state['values']);
     }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestClickedButtonForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestClickedButtonForm.php
index c8464c1..b0c4957 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestClickedButtonForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestClickedButtonForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder to test button click detection.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $first = NULL, $second = NULL, $third = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $first = NULL, $second = NULL, $third = NULL) {
     // A single text field. In IE, when a form has only one non-button input field
     // and the ENTER key is pressed while that field has focus, the form is
     // submitted without any information identifying the button responsible for
@@ -83,7 +84,7 @@ public function buildForm(array $form, array &$form_state, $first = NULL, $secon
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if (isset($form_state['triggering_element'])) {
       drupal_set_message(t('The clicked button is %name.', array('%name' => $form_state['triggering_element']['#name'])));
     }
@@ -95,7 +96,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message('Submit handler for form_test_clicked_button executed.');
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestColorForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestColorForm.php
index 0856026..3603631 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestColorForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestColorForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['color'] = array(
       '#type' => 'color',
       '#title' => 'Color',
@@ -40,7 +41,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
index 9f4e168..3555ab6 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Elements that take a simple default value.
     foreach (array('textfield', 'textarea', 'search', 'tel', 'hidden') as $type) {
       $form[$type] = array(
@@ -223,7 +224,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestEmailForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestEmailForm.php
index f46ec64..11bad32 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestEmailForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestEmailForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['email'] = array(
       '#type' => 'email',
       '#title' => 'Email address',
@@ -47,7 +48,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestEmptySelectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestEmptySelectForm.php
index 1434370..76e05ad 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestEmptySelectForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestEmptySelectForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a form to test select elements when #options is not an array.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['empty_select'] = array(
       '#type' => 'select',
       '#title' => t('Empty Select'),
@@ -37,7 +38,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateDatabaseForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateDatabaseForm.php
index f570e2b..a0dda13 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateDatabaseForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateDatabaseForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Database;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a form which gets the database connection stored in the form state.
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Text field'),
@@ -50,7 +51,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['cache'] = TRUE;
     $form_state['rebuild'] = TRUE;
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanAdvancedForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanAdvancedForm.php
index 879d7b3..79d44d7 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanAdvancedForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanAdvancedForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder for form_state_values_clean() test.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Build an example form containing a managed file and a submit form element.
     $form['image'] = array(
       '#type' => 'managed_file',
@@ -42,7 +43,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     form_state_values_clean($form_state);
     print t('You WIN!');
     exit;
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanForm.php
index 5c258d4..c8b39e3 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestFormStateValuesCleanForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder for form_state_values_clean() test.
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Build an example form containing multiple submit and button elements; not
     // only on the top-level.
     $form = array('#tree' => TRUE);
@@ -41,7 +42,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     form_state_values_clean($form_state);
     // This won't have a proper JSON header, but Drupal doesn't check for that
     // anyway so this is fine until it's replaced with a JsonResponse.
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupContainerForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupContainerForm.php
index 72c672e..26a04c4 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupContainerForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupContainerForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form to test the #group property on #type 'container'.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['container'] = array(
       '#type' => 'container',
     );
@@ -44,7 +45,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupDetailsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupDetailsForm.php
index fe94c13..d8f5925 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupDetailsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupDetailsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form to test the #group property on #type 'details'.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['details'] = array(
       '#type' => 'details',
       '#title' => 'Root element',
@@ -46,7 +47,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupFieldsetForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupFieldsetForm.php
index 5d4a7a8..e55b1af 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupFieldsetForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupFieldsetForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form to test the #group property on #type 'fieldset'.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['fieldset'] = array(
       '#type' => 'fieldset',
       '#title' => 'Fieldset',
@@ -44,7 +45,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php
index b92e22d..c4a11af 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form to test the #group property on #type 'vertical_tabs'.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['vertical_tabs'] = array(
       '#type' => 'vertical_tabs',
     );
@@ -52,7 +53,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestInputForgeryForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestInputForgeryForm.php
index d4f2493..e3a31e9 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestInputForgeryForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestInputForgeryForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 class FormTestInputForgeryForm extends FormBase {
@@ -22,7 +23,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // For testing that a user can't submit a value not matching one of the
     // allowed options.
     $form['checkboxes'] = array(
@@ -44,7 +45,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     return new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestLabelForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestLabelForm.php
index 2e24091..75234b0 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestLabelForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestLabelForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * A form for testing form labels and required marks.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['form_checkboxes_test'] = array(
       '#type' => 'checkboxes',
       '#title' => t('Checkboxes test'),
@@ -114,7 +115,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestLanguageSelectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestLanguageSelectForm.php
index 711b369..71d8311 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestLanguageSelectForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestLanguageSelectForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
@@ -26,7 +27,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['languages_all'] = array(
       '#title' => t('Languages: All'),
       '#type' => 'language_select',
@@ -65,7 +66,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestLimitValidationErrorsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestLimitValidationErrorsForm.php
index 6fdbb25..b8f4c52 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestLimitValidationErrorsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestLimitValidationErrorsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form with a button triggering partial validation.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['title'] = array(
       '#type' => 'textfield',
       '#title' => 'Title',
@@ -87,7 +88,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function elementValidateLimitValidationErrors($element, &$form_state) {
+  public function elementValidateLimitValidationErrors($element, FormStateInterface $form_state) {
     if ($element['#value'] == 'invalid') {
       form_error($element, $form_state, t('@label element is invalid', array('@label' => $element['#title'])));
     }
@@ -96,13 +97,13 @@ public function elementValidateLimitValidationErrors($element, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function partialSubmitForm(array &$form, array &$form_state) {
+  public function partialSubmitForm(array &$form, FormStateInterface $form_state) {
     // The title has not been validated, thus its value - in case of the test case
     // an empty string - may not be set.
     if (!isset($form_state['values']['title']) && isset($form_state['values']['test'])) {
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestNumberForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestNumberForm.php
index 7c313fc..e48f405 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestNumberForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestNumberForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a form to test #type 'number' and 'range' validation.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $element = 'number') {
+  public function buildForm(array $form, FormStateInterface $form_state, $element = 'number') {
     $base = array(
       '#type' => $element,
     );
@@ -139,7 +140,7 @@ public function buildForm(array $form, array &$form_state, $element = 'number')
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestPatternForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestPatternForm.php
index 7df5f7a..8a022b4 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestPatternForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestPatternForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a simple form using the FAPI #pattern proterty.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['textfield'] = array(
       '#type' => 'textfield',
       '#title' => 'One digit followed by lowercase letters',
@@ -59,7 +60,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestPlaceholderForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestPlaceholderForm.php
index f11d9d4..fc6c4dc 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestPlaceholderForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestPlaceholderForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a form to test the placeholder attribute.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     foreach (array('textfield', 'textarea', 'url', 'password', 'search', 'tel', 'email', 'number') as $type) {
       $form[$type] = array(
         '#type' => $type,
@@ -39,7 +40,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestProgrammaticForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestProgrammaticForm.php
index a44b8c4..68b4368 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestProgrammaticForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestProgrammaticForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder to test programmatic form submissions.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['textfield'] = array(
       '#title' => 'Textfield',
       '#type' => 'textfield',
@@ -87,7 +88,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if (empty($form_state['values']['textfield'])) {
       form_set_error('textfield', $form_state, t('Textfield is required.'));
     }
@@ -96,7 +97,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['storage']['programmatic_form_submit'] = $form_state['values'];
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeForm.php
index fff5126..34f1e52 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['with_default_value'] = array(
       '#type' => 'range',
       '#title' => 'Range with default value',
@@ -68,7 +69,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeInvalidForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeInvalidForm.php
index 7b685a7..92b2365 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeInvalidForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRangeInvalidForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form constructor for testing invalid #type 'range' elements.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['minmax'] = array(
       '#type' => 'range',
       '#min' => 10,
@@ -42,7 +43,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestRebuildPreserveValuesForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRebuildPreserveValuesForm.php
index e1ecced..2e6ed8b 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRebuildPreserveValuesForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRebuildPreserveValuesForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder for testing preservation of values during a rebuild.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Start the form with two checkboxes, to test different defaults, and a
     // textfield, to test more than one element type.
     $form = array(
@@ -85,7 +86,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function addMoreSubmitForm(array &$form, array &$form_state) {
+  public function addMoreSubmitForm(array &$form, FormStateInterface $form_state) {
     // Rebuild, to test preservation of input values.
     $form_state['storage']['add_more'] = TRUE;
     $form_state['rebuild'] = TRUE;
@@ -94,7 +95,7 @@ public function addMoreSubmitForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Finish the workflow. Do not rebuild.
     drupal_set_message(t('Form values: %values', array('%values' => var_export($form_state['values'], TRUE))));
   }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php
index 98219d9..0adc985 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRedirectForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder to detect form redirect.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['redirection'] = array(
       '#type' => 'checkbox',
       '#title' => t('Use redirection'),
@@ -49,7 +50,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['redirection'])) {
       $form_state['redirect'] = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
     }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestRequiredAttributeForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestRequiredAttributeForm.php
index 380d1c9..5f7d5d0 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestRequiredAttributeForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestRequiredAttributeForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Builds a form to test the required attribute.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     foreach (array('textfield', 'textarea', 'password') as $type) {
       $form[$type] = array(
         '#type' => $type,
@@ -39,7 +40,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestSelectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestSelectForm.php
index 5227ae4..eba498b 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestSelectForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestSelectForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $base = array(
       '#type' => 'select',
       '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
@@ -126,7 +127,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestStatePersistForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestStatePersistForm.php
index 5d948b0..f34f926 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestStatePersistForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestStatePersistForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form constructor for testing form state persistence.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['title'] = array(
       '#type' => 'textfield',
       '#title' => 'title',
@@ -43,7 +44,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($form_state['value']);
     $form_state['rebuild'] = TRUE;
   }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestStorageForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestStorageForm.php
index dadee26..742dac3 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestStorageForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestStorageForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * A multistep form for testing the form storage.
@@ -30,7 +31,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     if ($form_state['rebuild']) {
       $form_state['input'] = array();
     }
@@ -92,7 +93,7 @@ public function buildForm(array $form, array &$form_state) {
    *
    * Tests updating of cached form storage during validation.
    */
-  public function elementValidateValueCached($element, &$form_state) {
+  public function elementValidateValueCached($element, FormStateInterface $form_state) {
     // If caching is enabled and we receive a certain value, change the storage.
     // This presumes that another submitted form value triggers a validation error
     // elsewhere in the form. Form API should still update the cached form storage
@@ -105,7 +106,7 @@ public function elementValidateValueCached($element, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function continueSubmitForm(array &$form, array &$form_state) {
+  public function continueSubmitForm(array &$form, FormStateInterface $form_state) {
     $form_state['storage']['thing']['title'] = $form_state['values']['title'];
     $form_state['storage']['thing']['value'] = $form_state['values']['value'];
     $form_state['rebuild'] = TRUE;
@@ -114,7 +115,7 @@ public function continueSubmitForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message("Title: " . String::checkPlain($form_state['values']['title']));
     drupal_set_message("Form constructions: " . $_SESSION['constructions']);
     if (isset($form_state['storage']['thing']['changed'])) {
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectColspanForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectColspanForm.php
index 29c7e92..8c34d22 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectColspanForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectColspanForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\form_test\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 class FormTestTableSelectColspanForm extends FormTestTableSelectFormBase {
 
   /**
@@ -19,7 +21,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     list($header, $options) = _form_test_tableselect_get_data();
 
     // Change the data so that the third column has colspan=2.
@@ -42,7 +44,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectEmptyForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectEmptyForm.php
index 2bc690e..5d7dade 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectEmptyForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectEmptyForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\form_test\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 class FormTestTableSelectEmptyForm extends FormTestTableSelectFormBase {
 
   /**
@@ -19,14 +21,14 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     return $this->tableselectFormBuilder($form, $form_state, array('#options' => array()));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectFormBase.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectFormBase.php
index 863fe9b..c5186e2 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectFormBase.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectFormBase.php
@@ -19,8 +19,8 @@
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param $element_properties
    *   An array of element properties for the tableselect element.
    *
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectJsSelectForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectJsSelectForm.php
index c33ec77..c099163 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectJsSelectForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectJsSelectForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\form_test\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 class FormTestTableSelectJsSelectForm extends FormTestTableSelectFormBase {
 
   /**
@@ -19,7 +21,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $test_action = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $test_action = NULL) {
     switch ($test_action) {
       case 'multiple-true-default':
         $options = array('#multiple' => TRUE);
@@ -44,7 +46,7 @@ public function buildForm(array $form, array &$form_state, $test_action = NULL)
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleFalseForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleFalseForm.php
index c7545de..5f0b457 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleFalseForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleFalseForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\form_test\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 class FormTestTableSelectMultipleFalseForm extends FormTestTableSelectFormBase {
 
   /**
@@ -19,14 +21,14 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     return $this->tableselectFormBuilder($form, $form_state, array('#multiple' => FALSE));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message(t('Submitted: @value', array('@value' => $form_state['values']['tableselect'])));
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleTrueForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleTrueForm.php
index 28ea3bb..4d9a0e6 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleTrueForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectMultipleTrueForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\form_test\Form;
 
+use Drupal\Core\Form\FormStateInterface;
+
 class FormTestTableSelectMultipleTrueForm extends FormTestTableSelectFormBase {
 
   /**
@@ -19,14 +21,14 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     return $this->tableselectFormBuilder($form, $form_state, array('#multiple' => TRUE));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $selected = $form_state['values']['tableselect'];
     foreach ($selected as $key => $value) {
       drupal_set_message(t('Submitted: @key = @value', array('@key' => $key, '@value' => $value)));
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestUrlForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestUrlForm.php
index 8e2c5a0..297b604 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestUrlForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestUrlForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['url'] = array(
       '#type' => 'url',
       '#title' => 'Optional URL',
@@ -47,7 +48,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['response'] = new JsonResponse($form_state['values']);
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateForm.php
index 2e59a75..6467520 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\form_test\Callbacks;
 
 /**
@@ -34,7 +35,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $object = new Callbacks();
 
     $form['name'] = array(
@@ -58,7 +59,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if ($form_state['values']['name'] == 'validate') {
       // Alter the form element.
       $form['name']['#value'] = '#value changed by #validate';
@@ -75,7 +76,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredForm.php
index 65cb030..35908ad 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form constructor to test the #required property.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $options = array('foo' => 'foo', 'bar' => 'bar');
     $validate = array(array($this, 'elementValidateRequired'));
 
@@ -75,7 +76,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function elementValidateRequired($element, &$form_state) {
+  public function elementValidateRequired($element, FormStateInterface $form_state) {
     // Set a custom validation error on the #required element.
     if (!empty($element['#required_but_empty']) && isset($element['#form_test_required_error'])) {
       form_error($element, $form_state, $element['#form_test_required_error']);
@@ -85,7 +86,7 @@ public function elementValidateRequired($element, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message('The form_test_validate_required_form form was submitted successfully.');
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredNoTitleForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredNoTitleForm.php
index 25e5076..9beb455 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredNoTitleForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestValidateRequiredNoTitleForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form constructor to test the #required property without #title.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['textfield'] = array(
       '#type' => 'textfield',
       '#required' => TRUE,
@@ -37,7 +38,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message('The form_test_validate_required_form_no_title form was submitted successfully.');
   }
 
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestVerticalTabsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestVerticalTabsForm.php
index 4b35fbb..4a69660 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestVerticalTabsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestVerticalTabsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 class FormTestVerticalTabsForm extends FormBase {
 
@@ -21,7 +22,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['vertical_tabs'] = array(
       '#type' => 'vertical_tabs',
     );
@@ -52,7 +53,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/Form/RedirectBlockForm.php b/core/modules/system/tests/modules/form_test/src/Form/RedirectBlockForm.php
index 7d134d0..5f2fb52 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/RedirectBlockForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/RedirectBlockForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -27,7 +28,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Submit'));
 
@@ -37,7 +38,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['redirect_route'] = new Url('form_test.route1', array(), array('query' => array('test1' => 'test2')));
   }
 }
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php b/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
index 3f6703d..dd58435 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object that needs arguments.
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $arg = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $arg = NULL) {
     $form['element'] = array('#markup' => 'The FormTestArgumentsObject::buildForm() method was used for this form.');
 
     $form['bananas'] = array(
@@ -45,14 +46,14 @@ public function buildForm(array $form, array &$form_state, $arg = NULL) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestArgumentsObject::validateForm() method was used for this form.'));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestArgumentsObject::submitForm() method was used for this form.'));
     $this->config('form_test.object')
       ->set('bananas', $form_state['values']['bananas'])
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestAutocompleteForm.php b/core/modules/system/tests/modules/form_test/src/FormTestAutocompleteForm.php
index 6cedc3a..43daa5c 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestAutocompleteForm.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestAutocompleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a test form using autocomplete textfields.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['autocomplete_1'] = array(
       '#type' => 'textfield',
       '#title' => 'Autocomplete 1',
@@ -43,7 +44,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
index 6ddc7e0..4ccc8ad 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -33,7 +34,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $custom_attributes = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $custom_attributes = NULL) {
     $form['element'] = array('#markup' => 'The FormTestControllerObject::buildForm() method was used for this form.');
 
     $form['custom_attribute']['#markup'] = $custom_attributes;
@@ -55,14 +56,14 @@ public function buildForm(array $form, array &$form_state, $custom_attributes =
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestControllerObject::validateForm() method was used for this form.'));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestControllerObject::submitForm() method was used for this form.'));
     $this->config('form_test.object')
       ->set('bananas', $form_state['values']['bananas'])
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestObject.php b/core/modules/system/tests/modules/form_test/src/FormTestObject.php
index f6cb948..a6c6da3 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestObject.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['element'] = array('#markup' => 'The FormTestObject::buildForm() method was used for this form.');
 
     $form['bananas'] = array(
@@ -46,14 +47,14 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestObject::validateForm() method was used for this form.'));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestObject::submitForm() method was used for this form.'));
     $this->config('form_test.object')
       ->set('bananas', $form_state['values']['bananas'])
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php b/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
index 2861600..40682cb 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
@@ -8,6 +8,7 @@
 namespace Drupal\form_test;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['element'] = array('#markup' => 'The FormTestServiceObject::buildForm() method was used for this form.');
 
     $form['bananas'] = array(
@@ -44,14 +45,14 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestServiceObject::validateForm() method was used for this form.'));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestServiceObject::submitForm() method was used for this form.'));
     $this->config('form_test.object')
       ->set('bananas', $form_state['values']['bananas'])
diff --git a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
index 42c8830..36ab20c 100644
--- a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
+++ b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
@@ -8,6 +8,7 @@
 namespace Drupal\image_test\Plugin\ImageToolkit;
 
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\ImageToolkit\ImageToolkitBase;
 
 /**
@@ -60,7 +61,7 @@ public function settingsForm() {
   /**
    * {@inheritdoc}
    */
-  public function settingsFormSubmit($form, &$form_state) {
+  public function settingsFormSubmit($form, FormStateInterface $form_state) {
     \Drupal::config('system.image.test_toolkit')
       ->set('test_parameter', $form_state['values']['test']['test_parameter'])
       ->save();
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml b/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml
index d9e7a39..914fbd5 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.links.menu.yml
@@ -69,3 +69,13 @@ menu_test.menu-title-test.case3:
 menu_test.context:
   title: ''
   route_name: menu_test.context
+
+menu_test.parent:
+  title: 'Test menu_name parent'
+  route_name: menu_test.menu_name_test
+  menu_name: test
+
+menu_test.child:
+  title: 'Test menu_name child'
+  route_name: menu_test.menu_name_test
+  parent: menu_test.parent
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module
index c222ce8..b4f76a2 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.module
+++ b/core/modules/system/tests/modules/menu_test/menu_test.module
@@ -5,12 +5,10 @@
  * Module that implements various hooks for menu tests.
  */
 
-use Drupal\menu_link\Entity\MenuLink;
-
 /**
- * Implements hook_menu_link_defaults_alter().
+ * Implements hook_menu_links_discovered_alter().
  */
-function menu_test_menu_link_defaults_alter(&$links) {
+function menu_test_menu_links_discovered_alter(&$links) {
   // Many of the machine names here are slightly different from the route name.
   // Since the machine name is arbitrary, this helps ensure that core does not
   // add mistaken assumptions about the correlation.
@@ -97,29 +95,6 @@ function menu_test_callback() {
 }
 
 /**
- * Page callback: Tests menu_test_menu_tree_set_path().
- *
- * Retrieves the current menu path and if the menu path is not empty updates
- * the menu path that is used to determine the active menu trail.
- *
- * @return string
- *   A string that can be used for comparison.
- *
- * @see menu_test_menu().
- *
- * @deprecated Use \Drupal\menu_test\Controller\MenuTestController::menuTrail()
- */
-function menu_test_menu_trail_callback() {
-  $menu_path = \Drupal::state()->get('menu_test.menu_tree_set_path') ?: array();
-  /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-  $menu_tree = \Drupal::service('menu_link.tree');
-  if (!empty($menu_path)) {
-    $menu_tree->setPath($menu_path['menu_name'], $menu_path['path']);
-  }
-  return 'This is menu_test_menu_trail_callback().';
-}
-
-/**
  * Page callback: Tests the theme negotiation functionality.
  *
  * @param bool $inherited
@@ -167,44 +142,6 @@ function menu_test_menu_name($new_name = '') {
 }
 
 /**
- * Implements hook_ENTITY_TYPE_insert() for menu_link entities.
- */
-function menu_test_menu_link_insert(MenuLink $item) {
-  menu_test_static_variable('insert');
-}
-
-/**
- * Implements hook_ENTITY_TYPE_update() for menu_link entities.
- */
-function menu_test_menu_link_update(MenuLink $item) {
-  menu_test_static_variable('update');
-}
-
-/**
- * Implements hook_ENTITY_TYPE_delete() for menu_link entities.
- */
-function menu_test_menu_link_delete(MenuLink $item) {
-  menu_test_static_variable('delete');
-}
-
-/**
- * Sets a static variable for testing hook results.
- *
- * @param null|string $value
- *   (optional) The value to set or NULL to return the current value.
- *
- * @return null|string
- *   A text string for comparison to test assertions.
- */
-function menu_test_static_variable($value = NULL) {
-  static $variable;
-  if (!empty($value)) {
-    $variable = $value;
-  }
-  return $variable;
-}
-
-/**
  * Title callback: Concatenates the title and case number.
  *
  * @param string $title
diff --git a/core/modules/system/tests/modules/session_test/src/Form/SessionTestForm.php b/core/modules/system/tests/modules/session_test/src/Form/SessionTestForm.php
index 706c79c..3cf17f8 100644
--- a/core/modules/system/tests/modules/session_test/src/Form/SessionTestForm.php
+++ b/core/modules/system/tests/modules/session_test/src/Form/SessionTestForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for the test config edit forms.
@@ -25,7 +26,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['input'] = array(
       '#type' => 'textfield',
       '#title' => 'Input',
@@ -44,7 +45,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message(String::format('Ok: @input', array('@input' => $form_state['values']['input'])));
   }
 
diff --git a/core/modules/system/tests/modules/test_page_test/test_page_test.links.menu.yml b/core/modules/system/tests/modules/test_page_test/test_page_test.links.menu.yml
new file mode 100644
index 0000000..291fd70
--- /dev/null
+++ b/core/modules/system/tests/modules/test_page_test/test_page_test.links.menu.yml
@@ -0,0 +1,4 @@
+test_page_test.test_page:
+  route_name: test_page_test.test_page
+  title: 'Test front page link'
+  weight: 0
diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php
index ecfa229..09973a8 100644
--- a/core/modules/system/theme.api.php
+++ b/core/modules/system/theme.api.php
@@ -18,16 +18,16 @@
  * @link theme_render Theme system and Render API topic @endlink for more
  * information about render arrays and rendering.
  *
- * @section sec_theme_hooks Theme Hooks The theme system is invoked in
- * drupal_render() by calling the internal _theme() function, which operates on
- * the concept of "theme hooks". Theme hooks define how a particular type of
- * data should be rendered. They are registered by modules by implenting
- * hook_theme(), which specifies the name of the hook, the input "variables"
- * used to provide data and options, and other information. Modules implementing
- * hook_theme() also need to provide a default implementation for each of their
- * theme hooks, normally in a Twig file, and they may also provide preprocessing
- * functions. For example, the core Search module defines a theme hook for a
- * search result item in search_theme():
+ * @section sec_theme_hooks Theme Hooks
+ * The theme system is invoked in drupal_render() by calling the internal
+ * _theme() function, which operates on the concept of "theme hooks". Theme
+ * hooks define how a particular type of data should be rendered. They are
+ * registered by modules by implenting hook_theme(), which specifies the name of
+ * the hook, the input "variables" used to provide data and options, and other
+ * information. Modules implementing hook_theme() also need to provide a default
+ * implementation for each of their theme hooks, normally in a Twig file, and
+ * they may also provide preprocessing functions. For example, the core Search
+ * module defines a theme hook for a search result item in search_theme():
  * @code
  * return array(
  *   'search_result' => array(
@@ -153,6 +153,79 @@
  */
 
 /**
+ * @defgroup theme_render Theme system and Render API
+ * @{
+ * Overview of the Theme system and Render API.
+ *
+ * The main purpose of Drupal's Theme system is to give themes complete control
+ * over the appearance of the site, which includes the markup returned from HTTP
+ * requests and the CSS files used to style that markup. In order to ensure that
+ * a theme can completely customize the markup, module developers should avoid
+ * directly writing HTML markup for pages, blocks, and other user-visible output
+ * in their modules, and instead return structured "render arrays" (described
+ * below). Doing this also increases usability, by ensuring that the markup used
+ * for similar functionality on different areas of the site is the same, which
+ * gives users fewer user interface patterns to learn.
+ *
+ * The core structure of the Render API is the render array, which is a
+ * hierarchical associative array containing data to be rendered and properties
+ * describing how the data should be rendered. A render array that is returned
+ * by a function to specify markup to be sent to the web browser or other
+ * services will eventually be rendered by a call to drupal_render(), which will
+ * recurse through the render array hierarchy if appropriate, making calls into
+ * the theme system to do the actual rendering. If a function or method actually
+ * needs to return rendered output rather than a render array, the best practice
+ * would be to create a render array, render it by calling drupal_render(), and
+ * return that result, rather than writing the markup directly. See the
+ * documentation of drupal_render() for more details of the rendering process.
+ *
+ * Each level in the hierarchy of a render array (including the outermost array)
+ * has one or more array elements. Array elements whose names start with '#' are
+ * known as "properties", and the array elements with other names are "children"
+ * (constituting the next level of the hierarchy); the names of children are
+ * flexible, while property names are specific to the Render API and the
+ * particular type of data being rendered. A special case of render arrays is a
+ * form array, which specifies the form elements for an HTML form; see the
+ * @link form_api Form generation topic @endlink for more information on forms.
+ *
+ * Render arrays (at each level in the hierarchy) will usually have one of the
+ * following three properties defined:
+ * - #type: Specifies that the array contains data and options for a particular
+ *   type of "render element" (examples: 'form', for an HTML form; 'textfield',
+ *   'submit', and other HTML form element types; 'table', for a table with
+ *   rows, columns, and headers). Modules define render elements by implementing
+ *   hook_element_info(), which specifies the properties that are used in render
+ *   arrays to provide the data and options, and default values for these
+ *   properties. Look through implementations of hook_element_info() to discover
+ *   what render elements are available.
+ * - #theme: Specifies that the array contains data to be themed by a particular
+ *   theme hook. Modules define theme hooks by implementing hook_theme(), which
+ *   specifies the input "variables" used to provide data and options; if a
+ *   hook_theme() implementation specifies variable 'foo', then in a render
+ *   array, you would provide this data using property '#foo'. Modules
+ *   implementing hook_theme() also need to provide a default implementation for
+ *   each of their theme hooks, normally in a Twig file. For more information
+ *   and to discover available theme hooks, see the documentation of
+ *   hook_theme() and the
+ *   @link themeable Default theme implementations topic. @endlink
+ * - #markup: Specifies that the array provides HTML markup directly. Unless the
+ *   markup is very simple, such as an explanation in a paragraph tag, it is
+ *   normally preferable to use #theme or #type instead, so that the theme can
+ *   customize the markup.
+ *
+ * For further information on the Theme and Render APIs, see:
+ * - https://drupal.org/documentation/theme
+ * - https://drupal.org/developing/modules/8
+ * - https://drupal.org/node/722174
+ * - https://drupal.org/node/933976
+ * - https://drupal.org/node/930760
+ *
+ * @todo Check these links. Some are for Drupal 7, and might need updates for
+ *   Drupal 8.
+ * @}
+ */
+
+/**
  * Allow themes to alter the theme-specific settings form.
  *
  * With this hook, themes can alter the theme-specific settings form in any way
@@ -166,9 +239,9 @@
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
- *   A keyed array containing the current state of the form.
+ *   The current state of the form.
  */
-function hook_form_system_theme_settings_alter(&$form, &$form_state) {
+function hook_form_system_theme_settings_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
   // Add a checkbox to toggle the breadcrumb trail.
   $form['toggle_breadcrumb'] = array(
     '#type' => 'checkbox',
diff --git a/core/modules/taxonomy/src/Form/OverviewTerms.php b/core/modules/taxonomy/src/Form/OverviewTerms.php
index 4ff067a..23db546 100644
--- a/core/modules/taxonomy/src/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/src/Form/OverviewTerms.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\taxonomy\VocabularyInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -58,15 +59,15 @@ public function getFormId() {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary
    *   The vocabulary to display the overview form for.
    *
    * @return array
    *   The form structure.
    */
-  public function buildForm(array $form, array &$form_state, VocabularyInterface $taxonomy_vocabulary = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, VocabularyInterface $taxonomy_vocabulary = NULL) {
     // @todo Remove global variables when http://drupal.org/node/2044435 is in.
     global $pager_page_array, $pager_total, $pager_total_items;
 
@@ -360,10 +361,10 @@ public function buildForm(array $form, array &$form_state, VocabularyInterface $
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Sort term order based on weight.
     uasort($form_state['values']['terms'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
 
@@ -448,7 +449,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Redirects to confirmation form for the reset action.
    */
-  public function submitReset(array &$form, array &$form_state) {
+  public function submitReset(array &$form, FormStateInterface $form_state) {
     /** @var $vocabulary \Drupal\taxonomy\VocabularyInterface */
     $vocabulary = $form_state['taxonomy']['vocabulary'];
     $form_state['redirect_route'] = $vocabulary->urlInfo('reset');
diff --git a/core/modules/taxonomy/src/Form/TermDeleteForm.php b/core/modules/taxonomy/src/Form/TermDeleteForm.php
index 44d92b6..7851734 100644
--- a/core/modules/taxonomy/src/Form/TermDeleteForm.php
+++ b/core/modules/taxonomy/src/Form/TermDeleteForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -55,7 +56,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     $storage = $this->entityManager->getStorage('taxonomy_vocabulary');
     $vocabulary = $storage->load($this->entity->bundle());
diff --git a/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php b/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php
index 34d3da9..52348fb 100644
--- a/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php
+++ b/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -53,7 +54,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     drupal_set_message($this->t('Deleted vocabulary %name.', array('%name' => $this->entity->label())));
     watchdog('taxonomy', 'Deleted vocabulary %name.', array('%name' => $this->entity->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/taxonomy/src/Form/VocabularyResetForm.php b/core/modules/taxonomy/src/Form/VocabularyResetForm.php
index ef9e296..e32aec8 100644
--- a/core/modules/taxonomy/src/Form/VocabularyResetForm.php
+++ b/core/modules/taxonomy/src/Form/VocabularyResetForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\taxonomy\TermStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -80,7 +81,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $this->termStorage->resetWeights($this->entity->id());
     drupal_set_message($this->t('Reset vocabulary %name to alphabetical order.', array('%name' => $this->entity->label())));
     watchdog('taxonomy', 'Reset vocabulary %name to alphabetical order.', array('%name' => $this->entity->label()), WATCHDOG_NOTICE);
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php
index bae89fd..1dd7943 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceFieldItemList.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Field\EntityReferenceFieldItemList;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Represents a configurable taxonomy_term_reference entity field item list.
@@ -19,7 +20,7 @@ class TaxonomyTermReferenceFieldItemList extends EntityReferenceFieldItemList {
   /**
    * {@inheritdoc}
    */
-  public function defaultValuesFormSubmit(array $element, array &$form, array &$form_state) {
+  public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) {
     $default_value = parent::defaultValuesFormSubmit($element, $form, $form_state);
 
     // Convert numeric IDs to UUIDs to ensure config deployability.
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
index fb6a93e..865a802 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldType/TaxonomyTermReferenceItem.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\OptGroup;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\AllowedValuesInterface;
@@ -119,7 +120,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $vocabularies = entity_load_multiple('taxonomy_vocabulary');
     $options = array();
     foreach ($vocabularies as $vocabulary) {
@@ -151,7 +152,7 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     return array();
   }
 
diff --git a/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php b/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
index ae156a4..b3500fa 100644
--- a/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
+++ b/core/modules/taxonomy/src/Plugin/Field/FieldWidget/TaxonomyAutocompleteWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'taxonomy_autocomplete' widget.
@@ -38,7 +39,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['placeholder'] = array(
       '#type' => 'textfield',
       '#title' => t('Placeholder'),
@@ -69,7 +70,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $tags = array();
     if (!$items->isEmpty()) {
       foreach ($items as $item) {
@@ -96,7 +97,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function massageFormValues(array $values, array $form, array &$form_state) {
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
     // Autocomplete widgets do not send their tids in the form, so we must detect
     // them here and process them independently.
     $items = array();
diff --git a/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php b/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php
index d41e893..85c7b11 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\argument;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
 use Drupal\Component\Utility\String;
 
@@ -32,7 +33,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['depth'] = array(
       '#type' => 'weight',
       '#title' => t('Depth'),
diff --git a/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepthModifier.php b/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepthModifier.php
index ddfd1b9..077b1fd 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepthModifier.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepthModifier.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\argument;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
 
 /**
@@ -21,7 +22,7 @@
  */
 class IndexTidDepthModifier extends ArgumentPluginBase {
 
-  public function buildOptionsForm(&$form, &$form_state) { }
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) { }
 
   public function query($group_by = FALSE) { }
 
diff --git a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
index 6dfd7bd..d5c9c9d 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\argument_default;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\taxonomy\TermInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -55,7 +56,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['term_page'] = array(
       '#type' => 'checkbox',
       '#title' => t('Load default filter from term page'),
@@ -113,7 +114,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function submitOptionsForm(&$form, &$form_state, &$options = array()) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = array()) {
     // Filter unselected items so we don't unnecessarily store giant arrays.
     $options['vids'] = array_filter($options['vids']);
   }
diff --git a/core/modules/taxonomy/src/Plugin/views/argument_validator/TermName.php b/core/modules/taxonomy/src/Plugin/views/argument_validator/TermName.php
index d44b58c..3ed9258 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument_validator/TermName.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument_validator/TermName.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\argument_validator;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -53,7 +54,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['transform'] = array(
diff --git a/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php b/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php
index 295bb9c..a0b1e67 100644
--- a/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php
+++ b/core/modules/taxonomy/src/Plugin/views/field/LinkEdit.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -39,7 +40,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Text to display'),
diff --git a/core/modules/taxonomy/src/Plugin/views/field/Taxonomy.php b/core/modules/taxonomy/src/Plugin/views/field/Taxonomy.php
index 7700b27..59ced2d 100644
--- a/core/modules/taxonomy/src/Plugin/views/field/Taxonomy.php
+++ b/core/modules/taxonomy/src/Plugin/views/field/Taxonomy.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\area\Result;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -48,7 +49,7 @@ protected function defineOptions() {
   /**
    * Provide link to taxonomy option
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_taxonomy'] = array(
       '#title' => t('Link this field to its taxonomy term page'),
       '#description' => t("Enable to override this field's links."),
diff --git a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php
index 90e8225..5aac9e1 100644
--- a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\PrerenderList;
@@ -49,7 +50,7 @@ protected function defineOptions() {
   /**
    * Provide "link to term" option.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_taxonomy'] = array(
       '#title' => t('Link this field to its term page'),
       '#type' => 'checkbox',
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
index 2c708ea..c8f2381 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\filter\ManyToOne;
@@ -51,7 +52,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildExtraOptionsForm(&$form, &$form_state) {
+  public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
     $vocabularies = entity_load_multiple('taxonomy_vocabulary');
     $options = array();
     foreach ($vocabularies as $voc) {
@@ -95,7 +96,7 @@ public function buildExtraOptionsForm(&$form, &$form_state) {
     );
   }
 
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     $vocabulary = entity_load('taxonomy_vocabulary', $this->options['vid']);
     if (empty($vocabulary) && $this->options['limit']) {
       $form['markup'] = array(
@@ -212,7 +213,7 @@ protected function valueForm(&$form, &$form_state) {
     }
   }
 
-  protected function valueValidate($form, &$form_state) {
+  protected function valueValidate($form, FormStateInterface $form_state) {
     // We only validate if they've chosen the text field style.
     if ($this->options['type'] != 'textfield') {
       return;
@@ -253,7 +254,7 @@ public function acceptExposedInput($input) {
     return $rc;
   }
 
-  public function validateExposed(&$form, &$form_state) {
+  public function validateExposed(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed'])) {
       return;
     }
@@ -331,11 +332,11 @@ function validate_term_strings(&$form, $values) {
     return $tids;
   }
 
-  protected function valueSubmit($form, &$form_state) {
+  protected function valueSubmit($form, FormStateInterface $form_state) {
     // prevent array_filter from messing up our arrays in parent submit.
   }
 
-  public function buildExposeForm(&$form, &$form_state) {
+  public function buildExposeForm(&$form, FormStateInterface $form_state) {
     parent::buildExposeForm($form, $form_state);
     if ($this->options['type'] != 'select') {
       unset($form['expose']['reduce']);
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
index da0a61d..cb30f46 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\taxonomy\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Filter handler for taxonomy terms with depth.
  *
@@ -33,7 +35,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildExtraOptionsForm(&$form, &$form_state) {
+  public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildExtraOptionsForm($form, $form_state);
 
     $form['depth'] = array(
diff --git a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
index c720ee9..3483093 100644
--- a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
+++ b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\relationship;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\relationship\RelationshipPluginBase;
@@ -44,7 +45,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $vocabularies = entity_load_multiple('taxonomy_vocabulary');
     $options = array();
     foreach ($vocabularies as $voc) {
diff --git a/core/modules/taxonomy/src/TermForm.php b/core/modules/taxonomy/src/TermForm.php
index 851fa43..89aeac2 100644
--- a/core/modules/taxonomy/src/TermForm.php
+++ b/core/modules/taxonomy/src/TermForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy;
 
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
@@ -18,7 +19,7 @@ class TermForm extends ContentEntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $term = $this->entity;
     $vocab_storage = $this->entityManager->getStorage('taxonomy_vocabulary');
     $vocabulary = $vocab_storage->load($term->bundle());
@@ -107,7 +108,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     // Ensure numeric values.
@@ -119,7 +120,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     $term = parent::buildEntity($form, $form_state);
 
     // Prevent leading and trailing spaces in term names.
@@ -134,7 +135,7 @@ public function buildEntity(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $term = $this->entity;
 
     switch ($term->save()) {
diff --git a/core/modules/taxonomy/src/TermTranslationHandler.php b/core/modules/taxonomy/src/TermTranslationHandler.php
index 58cf864..3b8fbeb 100644
--- a/core/modules/taxonomy/src/TermTranslationHandler.php
+++ b/core/modules/taxonomy/src/TermTranslationHandler.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines the translation handler for terms.
@@ -18,7 +19,7 @@ class TermTranslationHandler extends ContentTranslationHandler {
   /**
    * {@inheritdoc}
    */
-  public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity) {
+  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
     parent::entityFormAlter($form, $form_state, $entity);
     $form['actions']['submit']['#submit'][] = array($this, 'entityFormSave');
   }
@@ -30,7 +31,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
    *
    * @see \Drupal\Core\Entity\EntityForm::build().
    */
-  function entityFormSave(array $form, array &$form_state) {
+  function entityFormSave(array $form, FormStateInterface $form_state) {
     if ($this->getSourceLangcode($form_state)) {
       $entity = content_translation_form_controller($form_state)->getEntity();
       // We need a redirect here, otherwise we would get an access denied page,
diff --git a/core/modules/taxonomy/src/VocabularyForm.php b/core/modules/taxonomy/src/VocabularyForm.php
index 95a986a..01ddc08 100644
--- a/core/modules/taxonomy/src/VocabularyForm.php
+++ b/core/modules/taxonomy/src/VocabularyForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
@@ -19,7 +20,7 @@ class VocabularyForm extends EntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $vocabulary = $this->entity;
     if ($vocabulary->isNew()) {
       $form['#title'] = $this->t('Add vocabulary');
@@ -88,7 +89,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     // If we are displaying the delete confirmation skip the regular actions.
     if (empty($form_state['confirm_delete'])) {
       $actions = parent::actions($form, $form_state);
@@ -114,7 +115,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * Submit handler to update the bundle for the default language configuration.
    */
-  public function languageConfigurationSubmit(array &$form, array &$form_state) {
+  public function languageConfigurationSubmit(array &$form, FormStateInterface $form_state) {
     $vocabulary = $this->entity;
     // Delete the old language settings for the vocabulary, if the machine name
     // is changed.
@@ -130,7 +131,7 @@ public function languageConfigurationSubmit(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $vocabulary = $this->entity;
 
     // Prevent leading and trailing spaces in vocabulary names.
diff --git a/core/modules/taxonomy/src/VocabularyListBuilder.php b/core/modules/taxonomy/src/VocabularyListBuilder.php
index c4fc1ad..056c073 100644
--- a/core/modules/taxonomy/src/VocabularyListBuilder.php
+++ b/core/modules/taxonomy/src/VocabularyListBuilder.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\Entity\DraggableListBuilder;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a class to build a listing of taxonomy vocabulary entities.
@@ -86,7 +87,7 @@ public function render() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
     $form['vocabularies']['#attributes'] = array('id' => 'taxonomy');
     $form['actions']['submit']['#value'] = t('Save');
@@ -97,7 +98,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     drupal_set_message(t('The configuration options have been saved.'));
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 62e0397..61ecb8b 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Entity\ContentEntityDatabaseStorage;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
@@ -708,7 +709,7 @@ function taxonomy_term_title(Term $term) {
 /**
  * Form element validate handler for taxonomy term autocomplete element.
  */
-function taxonomy_autocomplete_validate($element, &$form_state) {
+function taxonomy_autocomplete_validate($element, FormStateInterface $form_state) {
   // Split the values into an array.
   // @see \Drupal\taxonomy\Plugin\Field\FieldWidget\TaxonomyAutocompleteWidget:massageFormValues()
   $typed_terms = array();
diff --git a/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php b/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php
index 7dd4dee..5c65cf6 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldFormatter/TelephoneLinkFormatter.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'telephone_link' formatter.
@@ -35,7 +36,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $elements['title'] = array(
       '#type' => 'textfield',
       '#title' => t('Title to replace basic numeric telephone number display.'),
diff --git a/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php b/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
index 0bdd1c8..2be36da 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'telephone_default' widget.
@@ -35,7 +36,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['placeholder'] = array(
       '#type' => 'textfield',
       '#title' => t('Placeholder'),
@@ -65,7 +66,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element['value'] = $element + array(
       '#type' => 'tel',
       '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
diff --git a/core/modules/text/src/Plugin/Field/FieldFormatter/TextTrimmedFormatter.php b/core/modules/text/src/Plugin/Field/FieldFormatter/TextTrimmedFormatter.php
index 40c8dd0..8cd66c0 100644
--- a/core/modules/text/src/Plugin/Field/FieldFormatter/TextTrimmedFormatter.php
+++ b/core/modules/text/src/Plugin/Field/FieldFormatter/TextTrimmedFormatter.php
@@ -8,6 +8,7 @@
 
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'text_trimmed' formatter.
@@ -44,7 +45,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element['trim_length'] = array(
       '#title' => t('Trim length'),
       '#type' => 'number',
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
index 6bacea6..3b7285d 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\text\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'text' field type.
@@ -78,7 +79,7 @@ public function getConstraints() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array &$form, array &$form_state, $has_data) {
+  public function settingsForm(array &$form, FormStateInterface $form_state, $has_data) {
     $element = array();
 
     $element['max_length'] = array(
@@ -97,7 +98,7 @@ public function settingsForm(array &$form, array &$form_state, $has_data) {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
 
     $element['text_processing'] = array(
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php
index 367ae19..1c74a41 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextLongItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\text\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Plugin implementation of the 'text_long' field type.
@@ -48,7 +49,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
 
     $element['text_processing'] = array(
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
index 0d686e0..7ffcd64 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
@@ -8,6 +8,7 @@
 namespace Drupal\text\Plugin\Field\FieldType;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\TypedData\DataDefinition;
 
 /**
@@ -91,7 +92,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
-  public function instanceSettingsForm(array $form, array &$form_state) {
+  public function instanceSettingsForm(array $form, FormStateInterface $form_state) {
     $element = array();
     $settings = $this->getSettings();
 
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
index a8afeb3..ef6a5db 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextareaWidget;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -27,7 +28,7 @@ class TextareaWidget extends StringTextareaWidget {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $main_widget = parent::formElement($items, $delta, $element, $form, $form_state);
 
     if ($this->getFieldSetting('text_processing')) {
@@ -44,7 +45,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     if ($violation->arrayPropertyPath == array('format') && isset($element['format']['#access']) && !$element['format']['#access']) {
       // Ignore validation errors for formats if formats may not be changed,
       // i.e. when existing formats become invalid. See filter_process_format().
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php
index e23e794..ba8c875 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\text\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\text\Plugin\Field\FieldWidget\TextareaWidget;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 use Drupal\Core\Field\FieldItemListInterface;
@@ -38,7 +39,7 @@ public static function defaultSettings() {
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, array &$form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state) {
     $element = parent::settingsForm($form, $form_state);
     $element['summary_rows'] = array(
       '#type' => 'number',
@@ -64,7 +65,7 @@ public function settingsSummary() {
   /**
    * {@inheritdoc}
    */
-  function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element = parent::formElement($items, $delta, $element, $form, $form_state);
 
     $display_summary = $items[$delta]->summary || $this->getFieldSetting('display_summary');
@@ -89,7 +90,7 @@ function formElement(FieldItemListInterface $items, $delta, array $element, arra
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     $element = parent::errorElement($element, $violation, $form, $form_state);
     return ($element === FALSE) ? FALSE : $element[$violation->arrayPropertyPath[0]];
   }
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
index 989bcb8..c9b5dcd 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\StringWidget;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -28,7 +29,7 @@ class TextfieldWidget extends StringWidget {
   /**
    * {@inheritdoc}
    */
-  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $main_widget = parent::formElement($items, $delta, $element, $form, $form_state);
 
     if ($this->getFieldSetting('text_processing')) {
@@ -44,7 +45,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
   /**
    * {@inheritdoc}
    */
-  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, array &$form_state) {
+  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     if ($violation->arrayPropertyPath == array('format') && isset($element['format']['#access']) && !$element['format']['#access']) {
       // Ignore validation errors for formats if formats may not be changed,
       // i.e. when existing formats become invalid. See filter_process_format().
diff --git a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php
index a227a7f..c01ac71 100644
--- a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php
+++ b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php
@@ -125,30 +125,16 @@ function testModuleStatusChangeSubtreesHashCacheClear() {
   }
 
   /**
-   * Tests toolbar_menu_link_update() hook implementation.
+   * Tests toolbar cache tags implementation.
    */
   function testMenuLinkUpdateSubtreesHashCacheClear() {
-    // Get subtree items for the admin menu.
-    $query = \Drupal::entityQuery('menu_link');
-    for ($i = 1; $i <= 3; $i++) {
-      $query->sort('p' . $i, 'ASC');
-    }
-    $query->condition('menu_name', 'admin');
-    $query->condition('depth', '2', '>=');
-
-    // Build an ordered array of links using the query result object.
-    $links = array();
-    if ($result = $query->execute()) {
-      $links = menu_link_load_multiple($result);
-    }
-    // Get the first link in the set.
-    $links = array_values($links);
-    $link = array_shift($links);
+    // The ID of a (any) admin menu link.
+    $admin_menu_link_id = 'system.admin_config_development';
 
     // Disable the link.
     $edit = array();
     $edit['enabled'] = FALSE;
-    $this->drupalPostForm("admin/structure/menu/item/" . $link['mlid'] . "/edit", $edit, t('Save'));
+    $this->drupalPostForm("admin/structure/menu/link/" . $admin_menu_link_id . "/edit", $edit, t('Save'));
     $this->assertResponse(200);
     $this->assertText('The menu link has been saved.');
 
diff --git a/core/modules/toolbar/toolbar.info.yml b/core/modules/toolbar/toolbar.info.yml
index 269f7ec..6967bf6 100644
--- a/core/modules/toolbar/toolbar.info.yml
+++ b/core/modules/toolbar/toolbar.info.yml
@@ -6,4 +6,3 @@ package: Core
 version: VERSION
 dependencies:
   - breakpoint
-  - menu_link
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index d8e5363..d27a89e 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -6,13 +6,13 @@
  */
 
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Menu\MenuTreeParameters;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Template\Attribute;
 use Drupal\Component\Datetime\DateTimePlus;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\String;
-use Drupal\menu_link\MenuLinkInterface;
 use Drupal\user\RoleInterface;
 use Drupal\user\UserInterface;
 
@@ -326,8 +326,6 @@ function toolbar_pre_render_item($element) {
  * Implements hook_toolbar().
  */
 function toolbar_toolbar() {
-  $items = array();
-
   // The 'Home' tab is a simple link, with no corresponding tray.
   $items['home'] = array(
     '#type' => 'toolbar_item',
@@ -352,33 +350,13 @@ function toolbar_toolbar() {
     '#weight' => -20,
   );
 
-  // Retrieve the administration menu from the database.
-  $tree = toolbar_get_menu_tree();
-
-  // Add attributes to the links before rendering.
-  toolbar_menu_navigation_links($tree);
-
-  /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-  $menu_tree = \Drupal::service('menu_link.tree');
-
-  $menu = array(
-    '#heading' => t('Administration menu'),
-    'toolbar_administration' => array(
-      '#type' => 'container',
-      '#attributes' => array(
-        'class' => array('toolbar-menu-administration'),
-      ),
-      'administration_menu' => $menu_tree->renderTree($tree),
-    ),
-  );
-
   // To conserve bandwidth, we only include the top-level links in the HTML.
   // The subtrees are fetched through a JSONP script that is generated at the
   // toolbar_subtrees route. We provide the JavaScript requesting that JSONP
   // script here with the hash parameter that is needed for that route.
   // @see toolbar_subtrees_jsonp()
   $langcode = \Drupal::languageManager()->getCurrentLanguage()->id;
-  $menu['toolbar_administration']['#attached']['js'][] = array(
+  $subtrees_attached['js'][] = array(
     'type' => 'setting',
     'data' => array('toolbar' => array(
       'subtreesHash' => _toolbar_get_subtrees_hash($langcode),
@@ -405,7 +383,19 @@ function toolbar_toolbar() {
         'data-drupal-subtrees' => '',
       ),
     ),
-    'tray' => $menu,
+    'tray' => array(
+      '#heading' => t('Administration menu'),
+      '#attached' => $subtrees_attached,
+      'toolbar_administration' => array(
+        '#pre_render' => array(
+          'toolbar_prerender_toolbar_administration_tray',
+        ),
+        '#type' => 'container',
+        '#attributes' => array(
+          'class' => array('toolbar-menu-administration'),
+        ),
+      ),
+    ),
     '#weight' => -15,
   );
 
@@ -413,90 +403,102 @@ function toolbar_toolbar() {
 }
 
 /**
- * Gets only the top level items below the 'admin' path.
+ * Renders the toolbar's administration tray.
  *
- * @return
- *   An array containing a menu tree of top level items below the 'admin' path.
+ * @param array $element
+ *   A renderable array.
+ *
+ * @return array
+ *   The updated renderable array.
+ *
+ * @see drupal_render()
  */
-function toolbar_get_menu_tree() {
-  $tree = array();
-  /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-  $menu_tree = \Drupal::service('menu_link.tree');
-  $query = \Drupal::entityQuery('menu_link')
-    ->condition('menu_name', 'admin')
-    ->condition('module', 'system')
-    ->condition('link_path', 'admin');
-  $result = $query->execute();
-  if (!empty($result)) {
-    $admin_link = menu_link_load(reset($result));
-    $tree = $menu_tree->buildTree('admin', array(
-      'expanded' => array($admin_link['mlid']),
-      'min_depth' => $admin_link['depth'] + 1,
-      'max_depth' => $admin_link['depth'] + 1,
-    ));
-  }
-
-  return $tree;
+function toolbar_prerender_toolbar_administration_tray(array $element) {
+  $menu_tree = \Drupal::menuTree();
+  // Render the top-level administration menu links.
+  $parameters = new MenuTreeParameters();
+  $parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
+  $tree = $menu_tree->load(NULL, $parameters);
+  $manipulators = array(
+    array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+    array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    array('callable' => 'toolbar_menu_navigation_links'),
+  );
+  $tree = $menu_tree->transform($tree, $manipulators);
+  $element['administration_menu'] = $menu_tree->build($tree);
+  return $element;
 }
 
 /**
- * Generates an array of links from a menu tree array.
+ * Adds toolbar-specific attributes to the menu link tree.
  *
- * Based on menu_navigation_links(). Adds path based IDs and icon placeholders
- * to the links.
+ * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
+ *   The menu link tree to manipulate.
  *
- * @return
- *   An array of links as defined above.
+ * @return \Drupal\Core\Menu\MenuLinkTreeElement[]
+ *   The manipulated menu link tree.
  */
-function toolbar_menu_navigation_links(&$tree) {
-  foreach ($tree as $key => $item) {
-    // Configure sub-items.
-    if (!empty($item['below'])) {
-      toolbar_menu_navigation_links($tree[$key]['below']);
+function toolbar_menu_navigation_links(array $tree) {
+  foreach ($tree as $element) {
+    if ($element->subtree) {
+      toolbar_menu_navigation_links($element->subtree);
     }
+
     // Make sure we have a path specific ID in place, so we can attach icons
-    // and behaviors to the items.
-    $tree[$key]['link']['localized_options']['attributes'] = array(
-      'id' => 'toolbar-link-' . str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['link_path']),
-      'class' => array(
-        'toolbar-icon',
-        'toolbar-icon-' . strtolower(str_replace(' ', '-', $item['link']['link_title'])),
-      ),
-      'title' => String::checkPlain($item['link']['description']),
-    );
+    // and behaviors to the menu links.
+    $link = $element->link;
+    $url = $link->getUrlObject();
+    if ($url->isExternal()) {
+      // This is an unusual case, so just get a distinct, safe string.
+      $id = substr(Crypt::hashBase64($url->getPath()), 0, 16);
+    }
+    else {
+      $id = str_replace(array('.', '<', '>'), array('-', '', ''), $url->getRouteName());
+    }
+
+    // Get the non-localized title to make the icon class.
+    $definition = $link->getPluginDefinition();
+
+    $element->options['attributes']['id'] = 'toolbar-link-' . $id;
+    $element->options['attributes']['class'][] = 'toolbar-icon';
+    // @todo Change to use the plugin ID as class since titles might change.
+    //   https://www.drupal.org/node/2310365
+    $element->options['attributes']['class'][] = 'toolbar-icon-' . strtolower(str_replace(' ', '-', $definition['title']));
+    $element->options['attributes']['title'] = String::checkPlain($link->getDescription());
   }
+  return $tree;
 }
 
 /**
  * Returns the rendered subtree of each top-level toolbar link.
  */
 function toolbar_get_rendered_subtrees() {
+  $menu_tree = \Drupal::menuTree();
+  $parameters = new MenuTreeParameters();
+  $parameters->setRoot('system.admin')->excludeRoot()->setMaxDepth(3)->excludeHiddenLinks();
+  $tree = $menu_tree->load(NULL, $parameters);
+  $manipulators = array(
+    array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+    array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
+    array('callable' => 'toolbar_menu_navigation_links'),
+  );
+  $tree = $menu_tree->transform($tree, $manipulators);
   $subtrees = array();
-  /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-  $menu_tree = \Drupal::service('menu_link.tree');
-  $tree = toolbar_get_menu_tree();
-  foreach ($tree as $tree_item) {
-    $item = $tree_item['link'];
-    if (!$item['hidden'] && $item['access']) {
-      if ($item['has_children']) {
-        $query = \Drupal::entityQuery('menu_link')
-          ->condition('has_children', 1);
-        for ($i=1; $i <= $item['depth']; $i++) {
-          $query->condition('p' . $i, $item['p' . $i]);
-        }
-        $parents = $query->execute();
-        $subtree = $menu_tree->buildTree($item['menu_name'], array('expanded' => $parents, 'min_depth' => $item['depth']+1));
-        toolbar_menu_navigation_links($subtree);
-        $subtree = $menu_tree->renderTree($subtree);
-        $subtree = drupal_render($subtree);
-      }
-      else {
-        $subtree = '';
-      }
-
-      $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['link_path']);
-      $subtrees[$id] = $subtree;
+  foreach ($tree as $element) {
+    /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
+    $link = $element->link;
+    if ($element->subtree) {
+      $subtree = $menu_tree->build($element->subtree);
+      $output = drupal_render($subtree);
     }
+    else {
+      $output = '';
+    }
+    // Many routes have dots as route name, while some special ones like <front>
+    // have <> characters in them.
+    $id = str_replace(array('.', '<', '>'), array('-', '', '' ), $link->getUrlObject()->getRouteName());
+
+    $subtrees[$id] = $output;
   }
   return $subtrees;
 }
@@ -523,7 +525,7 @@ function _toolbar_get_subtrees_hash($langcode) {
     // caches later, based on the user's ID regardless of language.
     // Clear the cache when the 'locale' tag is deleted. This ensures a fresh
     // subtrees rendering when string translations are made.
-    \Drupal::cache('toolbar')->set($cid, $hash, Cache::PERMANENT, array('user' => array($uid), 'locale' => TRUE,));
+    \Drupal::cache('toolbar')->set($cid, $hash, Cache::PERMANENT, array('user' => array($uid), 'locale' => TRUE, 'menu' => 'admin'));
   }
   return $hash;
 }
@@ -543,15 +545,6 @@ function toolbar_modules_uninstalled($modules) {
 }
 
 /**
- * Implements hook_ENTITY_TYPE_update() for menu_link entities.
- */
-function toolbar_menu_link_update(MenuLinkInterface $menu_link) {
-  if ($menu_link->menu_name === 'admin') {
-    _toolbar_clear_user_cache();
-  }
-}
-
-/**
  * Implements hook_ENTITY_TYPE_update() for user entities.
  */
 function toolbar_user_update(UserInterface $user) {
diff --git a/core/modules/update/src/Form/UpdateManagerInstall.php b/core/modules/update/src/Form/UpdateManagerInstall.php
index e44cd0d..11b1ff6 100644
--- a/core/modules/update/src/Form/UpdateManagerInstall.php
+++ b/core/modules/update/src/Form/UpdateManagerInstall.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\FileTransfer\Local;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Updater\Updater;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -54,7 +55,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $this->moduleHandler->loadInclude('update', 'inc', 'update.manager');
     if (!_update_manager_check_backends($form, 'install')) {
       return $form;
@@ -101,7 +102,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $uploaded_file = $this->getRequest()->files->get('files[project_upload]', NULL, TRUE);
     if (!($form_state['values']['project_url'] XOR !empty($uploaded_file))) {
       $this->setFormError('project_url', $form_state, $this->t('You must either provide a URL or upload an archive file to install.'));
@@ -111,7 +112,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $local_cache = NULL;
     if ($form_state['values']['project_url']) {
       $local_cache = update_manager_file_get($form_state['values']['project_url']);
diff --git a/core/modules/update/src/Form/UpdateManagerUpdate.php b/core/modules/update/src/Form/UpdateManagerUpdate.php
index fd2cfb2..0f81361 100644
--- a/core/modules/update/src/Form/UpdateManagerUpdate.php
+++ b/core/modules/update/src/Form/UpdateManagerUpdate.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -65,7 +66,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $this->moduleHandler->loadInclude('update', 'inc', 'update.manager');
 
     $last_markup = array(
@@ -285,7 +286,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['projects'])) {
       $enabled = array_filter($form_state['values']['projects']);
     }
@@ -300,7 +301,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->moduleHandler->loadInclude('update', 'inc', 'update.manager');
     $projects = array();
     foreach (array('projects', 'disabled_projects') as $type) {
diff --git a/core/modules/update/src/Form/UpdateReady.php b/core/modules/update/src/Form/UpdateReady.php
index 57155f0..942164a 100644
--- a/core/modules/update/src/Form/UpdateReady.php
+++ b/core/modules/update/src/Form/UpdateReady.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\FileTransfer\Local;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\Updater\Updater;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -66,7 +67,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $this->moduleHandler->loadInclude('update', 'inc', 'update.manager');
     if (!_update_manager_check_backends($form, 'update')) {
       return $form;
@@ -96,7 +97,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Store maintenance_mode setting so we can restore it when done.
     $_SESSION['maintenance_mode'] = $this->state->get('system.maintenance_mode');
     if ($form_state['values']['maintenance_mode'] == TRUE) {
diff --git a/core/modules/update/src/UpdateSettingsForm.php b/core/modules/update/src/UpdateSettingsForm.php
index 600eaa2..7061081 100644
--- a/core/modules/update/src/UpdateSettingsForm.php
+++ b/core/modules/update/src/UpdateSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\update;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Configure update settings for this site.
@@ -22,9 +23,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $config = $this->config('update.settings');
 
     $form['update_check_frequency'] = array(
@@ -70,7 +71,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * Implements \Drupal\Core\Form\FormInterface::validateForm().
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state['notify_emails'] = array();
     if (!empty($form_state['values']['update_notify_emails'])) {
       $valid = array();
@@ -101,9 +102,9 @@ public function validateForm(array &$form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $config = $this->config('update.settings');
      // See if the update_check_disabled setting is being changed, and if so,
     // invalidate all update status data.
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index e34965e..3ba62cb 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -12,6 +12,7 @@
  */
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Site\Settings;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
@@ -261,7 +262,7 @@ function update_form_system_modules_alter(&$form, $form_state) {
  *
  * @see update_form_system_modules_alter()
  */
-function update_storage_clear_submit($form, &$form_state) {
+function update_storage_clear_submit($form, FormStateInterface $form_state) {
   // Clear all update module data.
   update_storage_clear();
 }
diff --git a/core/modules/user/config/install/views.view.who_s_new.yml b/core/modules/user/config/install/views.view.who_s_new.yml
index 7aa3a5d..0abe6e5 100644
--- a/core/modules/user/config/install/views.view.who_s_new.yml
+++ b/core/modules/user/config/install/views.view.who_s_new.yml
@@ -162,6 +162,7 @@ display:
     id: block_1
     display_title: 'Who''s new'
     position: 1
+    provider: block
     display_options:
       display_description: 'A list of new users'
       block_description: 'Who''s new'
@@ -174,3 +175,4 @@ langcode: en
 dependencies:
   module:
     - user
+    - block
diff --git a/core/modules/user/config/install/views.view.who_s_online.yml b/core/modules/user/config/install/views.view.who_s_online.yml
index 3b92c49..6040d38 100644
--- a/core/modules/user/config/install/views.view.who_s_online.yml
+++ b/core/modules/user/config/install/views.view.who_s_online.yml
@@ -193,6 +193,7 @@ display:
     id: who_s_online_block
     display_title: 'Who''s online'
     position: 1
+    provider: block
     display_options:
       block_description: 'Who''s online'
       display_description: 'A list of users that are currently logged in.'
@@ -204,3 +205,4 @@ langcode: en
 dependencies:
   module:
     - user
+    - block
diff --git a/core/modules/user/src/AccountForm.php b/core/modules/user/src/AccountForm.php
index f4f718b..a72c497 100644
--- a/core/modules/user/src/AccountForm.php
+++ b/core/modules/user/src/AccountForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\language\ConfigurableLanguageManagerInterface;
@@ -66,7 +67,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\user\UserInterface $account */
     $account = $this->entity;
     $user = $this->currentUser();
@@ -308,7 +309,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function buildEntity(array $form, array &$form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {
     // Change the roles array to a list of enabled roles.
     // @todo: Alter the form state as the form values are directly extracted and
     //   set on the field, which throws an exception as the list requires
@@ -324,7 +325,7 @@ public function buildEntity(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     $account = $this->entity;
@@ -391,7 +392,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     $user = $this->getEntity($form_state);
diff --git a/core/modules/user/src/AccountSettingsForm.php b/core/modules/user/src/AccountSettingsForm.php
index fa39ac2..06e1a09 100644
--- a/core/modules/user/src/AccountSettingsForm.php
+++ b/core/modules/user/src/AccountSettingsForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandler;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -56,9 +57,9 @@ public function getFormId() {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
     $config = $this->config('user.settings');
     $mail_config = $this->config('user.mail');
@@ -406,9 +407,9 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     $this->config('user.settings')
diff --git a/core/modules/user/src/Form/UserCancelForm.php b/core/modules/user/src/Form/UserCancelForm.php
index f9e8ead..031a27a 100644
--- a/core/modules/user/src/Form/UserCancelForm.php
+++ b/core/modules/user/src/Form/UserCancelForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a confirmation form for cancelling user account.
@@ -72,7 +73,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $user = $this->currentUser();
     $this->cancelMethods = user_cancel_methods();
 
@@ -117,7 +118,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     // Cancel account immediately, if the current user has administrative
     // privileges, no confirmation mail shall be sent, and the user does not
     // attempt to cancel the own account.
diff --git a/core/modules/user/src/Form/UserLoginForm.php b/core/modules/user/src/Form/UserLoginForm.php
index 6300bfc..9ba6217 100644
--- a/core/modules/user/src/Form/UserLoginForm.php
+++ b/core/modules/user/src/Form/UserLoginForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Flood\FloodInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\UserAuthInterface;
 use Drupal\user\UserStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -76,7 +77,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Display login form:
     $form['name'] = array(
       '#type' => 'textfield',
@@ -114,7 +115,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $account = $this->userStorage->load($form_state['uid']);
 
     // A destination was set, probably on an exception controller,
@@ -134,7 +135,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Sets an error if supplied username has been blocked.
    */
-  public function validateName(array &$form, array &$form_state) {
+  public function validateName(array &$form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
       // Blocked in user administration.
       $this->setFormError('name', $form_state, $this->t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
@@ -146,7 +147,7 @@ public function validateName(array &$form, array &$form_state) {
    *
    * If successful, $form_state['uid'] is set to the matching user ID.
    */
-  public function validateAuthentication(array &$form, array &$form_state) {
+  public function validateAuthentication(array &$form, FormStateInterface $form_state) {
     $password = trim($form_state['values']['pass']);
     $flood_config = $this->config('user.flood');
     if (!empty($form_state['values']['name']) && !empty($password)) {
@@ -193,7 +194,7 @@ public function validateAuthentication(array &$form, array &$form_state) {
    *
    * This validation function should always be the last one.
    */
-  public function validateFinal(array &$form, array &$form_state) {
+  public function validateFinal(array &$form, FormStateInterface $form_state) {
     $flood_config = $this->config('user.flood');
     if (empty($form_state['uid'])) {
       // Always register an IP-based failed login event.
diff --git a/core/modules/user/src/Form/UserMultipleCancelConfirm.php b/core/modules/user/src/Form/UserMultipleCancelConfirm.php
index 1d918ab..430480a 100644
--- a/core/modules/user/src/Form/UserMultipleCancelConfirm.php
+++ b/core/modules/user/src/Form/UserMultipleCancelConfirm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Url;
 use Drupal\user\TempStoreFactory;
@@ -101,7 +102,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Retrieve the accounts to be canceled from the temp store.
     $accounts = $this->tempStoreFactory
       ->get('user_user_operations_cancel')
@@ -168,7 +169,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $current_user_id = $this->currentUser()->id();
 
     // Clear out the accounts from the temp store.
diff --git a/core/modules/user/src/Form/UserPasswordForm.php b/core/modules/user/src/Form/UserPasswordForm.php
index 672dc11..5905282 100644
--- a/core/modules/user/src/Form/UserPasswordForm.php
+++ b/core/modules/user/src/Form/UserPasswordForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Field\Plugin\Field\FieldType\EmailItem;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\user\UserStorageInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -69,7 +70,7 @@ public function getFormId() {
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['name'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('Username or email address'),
@@ -106,7 +107,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $name = trim($form_state['values']['name']);
     // Try to load by email.
     $users = $this->userStorage->loadByProperties(array('mail' => $name, 'status' => '1'));
@@ -126,7 +127,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $langcode = $this->languageManager->getCurrentLanguage()->id;
 
     $account = $form_state['values']['account'];
diff --git a/core/modules/user/src/Form/UserPasswordResetForm.php b/core/modules/user/src/Form/UserPasswordResetForm.php
index ba7c121..41c6e1a 100644
--- a/core/modules/user/src/Form/UserPasswordResetForm.php
+++ b/core/modules/user/src/Form/UserPasswordResetForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Form\FormBase;
@@ -56,8 +57,8 @@ public function getFormID() {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\Core\Session\AccountInterface $user
    *   User requesting reset.
    * @param string $expiration_date
@@ -68,7 +69,7 @@ public function getFormID() {
    * @param string $hash
    *   Login link hash.
    */
-  public function buildForm(array $form, array &$form_state, AccountInterface $user = NULL, $expiration_date = NULL, $timestamp = NULL, $hash = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, AccountInterface $user = NULL, $expiration_date = NULL, $timestamp = NULL, $hash = NULL) {
     if ($expiration_date) {
       $form['message'] = array('#markup' => $this->t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $user->getUsername(), '%expiration_date' => $expiration_date)));
     }
@@ -98,7 +99,7 @@ public function buildForm(array $form, array &$form_state, AccountInterface $use
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     /** @var $user \Drupal\user\UserInterface */
     $user = $form_state['values']['user'];
     user_login_finalize($user);
diff --git a/core/modules/user/src/Form/UserPermissionsForm.php b/core/modules/user/src/Form/UserPermissionsForm.php
index bd4e473..8e5ac1d 100644
--- a/core/modules/user/src/Form/UserPermissionsForm.php
+++ b/core/modules/user/src/Form/UserPermissionsForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\RoleStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -75,7 +76,7 @@ protected function getRoles() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $role_names = array();
     $role_permissions = array();
     foreach ($this->getRoles() as $role_name => $role) {
@@ -184,7 +185,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  function submitForm(array &$form, array &$form_state) {
+  function submitForm(array &$form, FormStateInterface $form_state) {
     foreach ($form_state['values']['role_names'] as $role_name => $name) {
       user_role_change_permissions($role_name, $form_state['values'][$role_name]);
     }
diff --git a/core/modules/user/src/Form/UserPermissionsRoleSpecificForm.php b/core/modules/user/src/Form/UserPermissionsRoleSpecificForm.php
index 6345a06..3da670d 100644
--- a/core/modules/user/src/Form/UserPermissionsRoleSpecificForm.php
+++ b/core/modules/user/src/Form/UserPermissionsRoleSpecificForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\RoleInterface;
 
 /**
@@ -34,7 +35,7 @@ protected function getRoles() {
    * @param string $role_id
    *   The user role ID used for this form.
    */
-  public function buildForm(array $form, array &$form_state, RoleInterface $user_role = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, RoleInterface $user_role = NULL) {
     $this->userRole = $user_role;
     return parent::buildForm($form, $form_state);
   }
diff --git a/core/modules/user/src/Form/UserRoleDelete.php b/core/modules/user/src/Form/UserRoleDelete.php
index 9ac6ad0..4288170 100644
--- a/core/modules/user/src/Form/UserRoleDelete.php
+++ b/core/modules/user/src/Form/UserRoleDelete.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Form;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,7 +40,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->delete();
     watchdog('user', 'Role %name has been deleted.', array('%name' => $this->entity->label()));
     drupal_set_message($this->t('Role %name has been deleted.', array('%name' => $this->entity->label())));
diff --git a/core/modules/user/src/Plugin/Action/ChangeUserRoleBase.php b/core/modules/user/src/Plugin/Action/ChangeUserRoleBase.php
index f844743..c6fb44a 100644
--- a/core/modules/user/src/Plugin/Action/ChangeUserRoleBase.php
+++ b/core/modules/user/src/Plugin/Action/ChangeUserRoleBase.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Action\ConfigurableActionBase;
 use Drupal\Core\Entity\DependencyTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -59,7 +60,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $roles = user_role_names(TRUE);
     unset($roles[DRUPAL_AUTHENTICATED_RID]);
     $form['rid'] = array(
@@ -75,7 +76,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['rid'] = $form_state['values']['rid'];
   }
 
diff --git a/core/modules/user/src/Plugin/Condition/UserRole.php b/core/modules/user/src/Plugin/Condition/UserRole.php
index 872b18a..5400d4e 100644
--- a/core/modules/user/src/Plugin/Condition/UserRole.php
+++ b/core/modules/user/src/Plugin/Condition/UserRole.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\Condition;
 
 use Drupal\Core\Condition\ConditionPluginBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\Context\ContextDefinition;
 
 /**
@@ -27,7 +28,7 @@ class UserRole extends ConditionPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form['roles'] = array(
       '#type' => 'checkboxes',
       '#title' => $this->t('When the user has the following roles'),
@@ -50,7 +51,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function submitConfigurationForm(array &$form, array &$form_state) {
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     $this->configuration['roles'] = array_filter($form_state['values']['roles']);
     parent::submitConfigurationForm($form, $form_state);
   }
diff --git a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
index cc0bfb5..cdd2695 100644
--- a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
+++ b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
@@ -7,12 +7,14 @@
 
 namespace Drupal\user\Plugin\LanguageNegotiation;
 
+use Drupal\Core\PathProcessor\PathProcessorManager;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\AdminContext;
 use Drupal\language\LanguageNegotiationMethodBase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
 use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
 
 /**
@@ -51,16 +53,26 @@ class LanguageNegotiationUserAdmin extends LanguageNegotiationMethodBase impleme
   protected $router;
 
   /**
+   * The path processor manager.
+   *
+   * @var \Drupal\Core\PathProcessor\PathProcessorManager
+   */
+  protected $pathProcessorManager;
+
+  /**
    * Constructs a new LanguageNegotiationUserAdmin instance.
    *
    * @param \Drupal\Core\Routing\AdminContext $admin_context
    *   The admin context.
    * @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $router
    *   The router.
+   * @param \Drupal\Core\PathProcessor\PathProcessorManager $path_processor_manager
+   *   The path processor manager.
    */
-  public function __construct(AdminContext $admin_context, UrlMatcherInterface $router) {
+  public function __construct(AdminContext $admin_context, UrlMatcherInterface $router, PathProcessorManager $path_processor_manager) {
     $this->adminContext = $admin_context;
     $this->router = $router;
+    $this->pathProcessorManager = $path_processor_manager;
   }
 
   /**
@@ -69,7 +81,8 @@ public function __construct(AdminContext $admin_context, UrlMatcherInterface $ro
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
     return new static(
       $container->get('router.admin_context'),
-      $container->get('router')
+      $container->get('router'),
+      $container->get('path_processor_manager')
     );
   }
 
@@ -105,10 +118,20 @@ public function getLangcode(Request $request = NULL) {
   public function isAdminPath(Request $request) {
     $result = FALSE;
     if ($request && $this->adminContext) {
-      // If called from an event subscriber, the request may not the route info
-      // yet, so use the router to look up the path first.
+      // If called from an event subscriber, the request may not have the route
+      // object yet (it is still being built), so use the router to look up
+      // based on the path.
       if (!$route_object = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) {
-        $attributes = $this->router->match('/' . urldecode(trim($request->getPathInfo(), '/')));
+        try {
+          // Process the path as an inbound path. This will remove any language
+          // prefixes and other path components that inbound processing would
+          // clear out, so we can attempt to load the route clearly.
+          $path = $this->pathProcessorManager->processInbound(urldecode(trim($request->getPathInfo(), '/')), $request);
+          $attributes = $this->router->match('/' . $path);
+        }
+        catch (ResourceNotFoundException $e) {
+          return FALSE;
+        }
         $route_object = $attributes[RouteObjectInterface::ROUTE_OBJECT];
       }
       $result = $this->adminContext->isAdminRoute($route_object);
diff --git a/core/modules/user/src/Plugin/Menu/MyAccountMenuLink.php b/core/modules/user/src/Plugin/Menu/MyAccountMenuLink.php
new file mode 100644
index 0000000..91768cd
--- /dev/null
+++ b/core/modules/user/src/Plugin/Menu/MyAccountMenuLink.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Plugin\Menu\MyAccountMenuLink.
+ */
+
+namespace Drupal\user\Plugin\Menu;
+
+use Drupal\Core\Menu\MenuLinkDefault;
+
+/**
+ * Provides custom logic for the user.page menu link.
+ */
+class MyAccountMenuLink extends MenuLinkDefault {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isHidden() {
+    // The path 'user' must be accessible for anonymous users, but only visible
+    // for authenticated users. Authenticated users should see "My account", but
+    // anonymous users should not see it at all.
+    // @todo Re-write this as a link to user.view with dynamic route parameters
+    //   to affect access since hidden should not be dynamic.
+    //   https://www.drupal.org/node/2306991
+    return $this->pluginDefinition['hidden'] || \Drupal::currentUser()->isAnonymous();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isCacheable() {
+    return FALSE;
+  }
+
+}
diff --git a/core/modules/user/src/Plugin/views/access/Permission.php b/core/modules/user/src/Plugin/views/access/Permission.php
index 7797913..bc5a5fa 100644
--- a/core/modules/user/src/Plugin/views/access/Permission.php
+++ b/core/modules/user/src/Plugin/views/access/Permission.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\access;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
 use Symfony\Component\Routing\Route;
@@ -60,7 +61,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $perms = array();
     $module_info = system_get_info('module');
diff --git a/core/modules/user/src/Plugin/views/access/Role.php b/core/modules/user/src/Plugin/views/access/Role.php
index 496c9d7..c63a5a4 100644
--- a/core/modules/user/src/Plugin/views/access/Role.php
+++ b/core/modules/user/src/Plugin/views/access/Role.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\access;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\access\AccessPluginBase;
 use Symfony\Component\Routing\Route;
 use Drupal\Core\Session\AccountInterface;
@@ -69,7 +70,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['role'] = array(
       '#type' => 'checkboxes',
@@ -80,13 +81,13 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     if (!array_filter($form_state['values']['access_options']['role'])) {
       form_error($form['role'], $form_state, t('You must select at least one role if type is "by role"'));
     }
   }
 
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     // I hate checkboxes.
     $form_state['values']['access_options']['role'] = array_filter($form_state['values']['access_options']['role']);
   }
diff --git a/core/modules/user/src/Plugin/views/argument_default/User.php b/core/modules/user/src/Plugin/views/argument_default/User.php
index fad8743..d218e06 100644
--- a/core/modules/user/src/Plugin/views/argument_default/User.php
+++ b/core/modules/user/src/Plugin/views/argument_default/User.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\argument_default;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -36,7 +37,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['user'] = array(
       '#type' => 'checkbox',
       '#title' => t('Also look for a node and use the node author'),
diff --git a/core/modules/user/src/Plugin/views/argument_validator/User.php b/core/modules/user/src/Plugin/views/argument_validator/User.php
index 25d23b2..c6acd86 100644
--- a/core/modules/user/src/Plugin/views/argument_validator/User.php
+++ b/core/modules/user/src/Plugin/views/argument_validator/User.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\argument_validator\Entity;
 
 /**
@@ -51,7 +52,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $sanitized_id = ArgumentPluginBase::encodeValidatorId($this->definition['id']);
 
@@ -78,7 +79,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitOptionsForm(&$form, &$form_state, &$options = array()) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = array()) {
     // filter trash out of the options so we don't store giant unnecessary arrays
     $options['roles'] = array_filter($options['roles']);
   }
diff --git a/core/modules/user/src/Plugin/views/argument_validator/UserName.php b/core/modules/user/src/Plugin/views/argument_validator/UserName.php
index daf50b3..057389b 100644
--- a/core/modules/user/src/Plugin/views/argument_validator/UserName.php
+++ b/core/modules/user/src/Plugin/views/argument_validator/UserName.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\user\Plugin\views\argument_validator;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Validates whether a user name is valid.
  *
@@ -21,7 +23,7 @@ class UserName extends User {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $entity_type = $this->entityManager->getDefinition('user');
diff --git a/core/modules/user/src/Plugin/views/field/Link.php b/core/modules/user/src/Plugin/views/field/Link.php
index 1300de5..40ff364 100644
--- a/core/modules/user/src/Plugin/views/field/Link.php
+++ b/core/modules/user/src/Plugin/views/field/Link.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -45,7 +46,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Text to display'),
diff --git a/core/modules/user/src/Plugin/views/field/Mail.php b/core/modules/user/src/Plugin/views/field/Mail.php
index 2908526..ad26317 100644
--- a/core/modules/user/src/Plugin/views/field/Mail.php
+++ b/core/modules/user/src/Plugin/views/field/Mail.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -24,7 +25,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['link_to_user'] = array(
       '#title' => t('Link this field'),
diff --git a/core/modules/user/src/Plugin/views/field/Name.php b/core/modules/user/src/Plugin/views/field/Name.php
index fa924d7..5396bc6 100644
--- a/core/modules/user/src/Plugin/views/field/Name.php
+++ b/core/modules/user/src/Plugin/views/field/Name.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\field;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\Plugin\views\field\User;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -48,7 +49,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['format_username'] = array(
diff --git a/core/modules/user/src/Plugin/views/field/User.php b/core/modules/user/src/Plugin/views/field/User.php
index ef04e9c..d49c7e1 100644
--- a/core/modules/user/src/Plugin/views/field/User.php
+++ b/core/modules/user/src/Plugin/views/field/User.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -41,7 +42,7 @@ protected function defineOptions() {
   /**
    * Provide link to node option
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_user'] = array(
       '#title' => t('Link this field to its user'),
       '#description' => t("Enable to override this field's links."),
diff --git a/core/modules/user/src/Plugin/views/field/UserBulkForm.php b/core/modules/user/src/Plugin/views/field/UserBulkForm.php
index 3811eae..943cd9b 100644
--- a/core/modules/user/src/Plugin/views/field/UserBulkForm.php
+++ b/core/modules/user/src/Plugin/views/field/UserBulkForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\system\Plugin\views\field\BulkForm;
 use Drupal\user\UserInterface;
 
@@ -23,7 +24,7 @@ class UserBulkForm extends BulkForm {
    *
    * Provide a more useful title to improve the accessibility.
    */
-  public function viewsForm(&$form, &$form_state) {
+  public function viewsForm(&$form, FormStateInterface $form_state) {
     parent::viewsForm($form, $form_state);
 
     if (!empty($this->view->result)) {
diff --git a/core/modules/user/src/Plugin/views/field/UserData.php b/core/modules/user/src/Plugin/views/field/UserData.php
index b58c3fc..cb9f35b 100644
--- a/core/modules/user/src/Plugin/views/field/UserData.php
+++ b/core/modules/user/src/Plugin/views/field/UserData.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
@@ -63,7 +64,7 @@ protected function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::defineOptions().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $modules = system_get_info('module');
diff --git a/core/modules/user/src/Plugin/views/filter/Name.php b/core/modules/user/src/Plugin/views/filter/Name.php
index 0d1b5fc..8bdb001 100644
--- a/core/modules/user/src/Plugin/views/filter/Name.php
+++ b/core/modules/user/src/Plugin/views/filter/Name.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\filter;
 
 use Drupal\Component\Utility\Tags;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\filter\InOperator;
 
 /**
@@ -21,7 +22,7 @@ class Name extends InOperator {
 
   protected $alwaysMultiple = TRUE;
 
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     $values = array();
     if ($this->value) {
       $result = entity_load_multiple_by_properties('user', array('uid' => $this->value));
@@ -50,7 +51,7 @@ protected function valueForm(&$form, &$form_state) {
     }
   }
 
-  protected function valueValidate($form, &$form_state) {
+  protected function valueValidate($form, FormStateInterface $form_state) {
     $values = Tags::explode($form_state['values']['options']['value']);
     $uids = $this->validate_user_strings($form['value'], $form_state, $values);
 
@@ -72,7 +73,7 @@ public function acceptExposedInput($input) {
     return $rc;
   }
 
-  public function validateExposed(&$form, &$form_state) {
+  public function validateExposed(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed'])) {
       return;
     }
@@ -108,7 +109,7 @@ public function validateExposed(&$form, &$form_state) {
    * or the exposed filter, this is abstracted out a bit so it can
    * handle the multiple input sources.
    */
-  function validate_user_strings(&$form, array &$form_state, $values) {
+  function validate_user_strings(&$form, FormStateInterface $form_state, $values) {
     $uids = array();
     $placeholders = array();
     $args = array();
@@ -140,7 +141,7 @@ function validate_user_strings(&$form, array &$form_state, $values) {
     return $uids;
   }
 
-  protected function valueSubmit($form, &$form_state) {
+  protected function valueSubmit($form, FormStateInterface $form_state) {
     // prevent array filter from removing our anonymous user.
   }
 
diff --git a/core/modules/user/src/ProfileForm.php b/core/modules/user/src/ProfileForm.php
index fbe7665..c7c74c5 100644
--- a/core/modules/user/src/ProfileForm.php
+++ b/core/modules/user/src/ProfileForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManager;
 
 /**
@@ -26,7 +27,7 @@ public function __construct(EntityManagerInterface $entity_manager, LanguageMana
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $element = parent::actions($form, $form_state);
 
     // The user account being edited.
@@ -45,7 +46,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $account = $this->entity;
     $account->save();
     $form_state['values']['uid'] = $account->id();
@@ -56,7 +57,7 @@ public function save(array $form, array &$form_state) {
   /**
    * Provides a submit handler for the 'Cancel account' button.
    */
-  public function editCancelSubmit($form, &$form_state) {
+  public function editCancelSubmit($form, FormStateInterface $form_state) {
     $destination = array();
     $query = $this->getRequest()->query;
     if ($query->has('destination')) {
diff --git a/core/modules/user/src/ProfileTranslationHandler.php b/core/modules/user/src/ProfileTranslationHandler.php
index c332d83..fd9c90b 100644
--- a/core/modules/user/src/ProfileTranslationHandler.php
+++ b/core/modules/user/src/ProfileTranslationHandler.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines the translation handler for users.
@@ -18,7 +19,7 @@ class ProfileTranslationHandler extends ContentTranslationHandler {
   /**
    * {@inheritdoc}
    */
-  public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity) {
+  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
     parent::entityFormAlter($form, $form_state, $entity);
     $form['actions']['submit']['#submit'][] = array($this, 'entityFormSave');
   }
@@ -30,7 +31,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
    *
    * @see \Drupal\Core\Entity\EntityForm::build().
    */
-  function entityFormSave(array $form, array &$form_state) {
+  function entityFormSave(array $form, FormStateInterface $form_state) {
     if ($this->getSourceLangcode($form_state)) {
       $entity = content_translation_form_controller($form_state)->getEntity();
       // We need a redirect here, otherwise we would get an access denied page
diff --git a/core/modules/user/src/RegisterForm.php b/core/modules/user/src/RegisterForm.php
index ddbbcc0..f3f2511 100644
--- a/core/modules/user/src/RegisterForm.php
+++ b/core/modules/user/src/RegisterForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManager;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -25,9 +26,9 @@ public function __construct(EntityManagerInterface $entity_manager, LanguageMana
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityForm::form().
+   * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $user = $this->currentUser();
     /** @var \Drupal\user\UserInterface $account */
     $account = $this->entity;
@@ -71,7 +72,7 @@ public function form(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::actions().
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $element = parent::actions($form, $form_state);
     $element['submit']['#value'] = $this->t('Create new account');
     return $element;
@@ -80,7 +81,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::submit().
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $admin = $form_state['values']['administer_users'];
 
     if (!\Drupal::config('user.settings')->get('verify_mail') || $admin) {
@@ -102,7 +103,7 @@ public function submit(array $form, array &$form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::submit().
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $account = $this->entity;
     $pass = $account->getPassword();
     $admin = $form_state['values']['administer_users'];
diff --git a/core/modules/user/src/RoleForm.php b/core/modules/user/src/RoleForm.php
index 1961a75..0587041 100644
--- a/core/modules/user/src/RoleForm.php
+++ b/core/modules/user/src/RoleForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for the role entity edit forms.
@@ -18,7 +19,7 @@ class RoleForm extends EntityForm {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
     $form['label'] = array(
       '#type' => 'textfield',
@@ -51,7 +52,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, array &$form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $entity = $this->entity;
 
     // Prevent leading and trailing spaces in role names.
diff --git a/core/modules/user/src/RoleListBuilder.php b/core/modules/user/src/RoleListBuilder.php
index afe8d7b..8e7feec 100644
--- a/core/modules/user/src/RoleListBuilder.php
+++ b/core/modules/user/src/RoleListBuilder.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\Entity\DraggableListBuilder;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Defines a class to build a listing of user role entities.
@@ -58,7 +59,7 @@ public function getDefaultOperations(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
     drupal_set_message(t('The role settings have been updated.'));
diff --git a/core/modules/user/src/Tests/UserAccountFormFieldsTest.php b/core/modules/user/src/Tests/UserAccountFormFieldsTest.php
index b560a0c..47849b9 100644
--- a/core/modules/user/src/Tests/UserAccountFormFieldsTest.php
+++ b/core/modules/user/src/Tests/UserAccountFormFieldsTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Tests;
 
+use Drupal\Core\Form\FormState;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
@@ -30,7 +31,7 @@ class UserAccountFormFieldsTest extends DrupalUnitTestBase {
   function testInstallConfigureForm() {
     require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
     $install_state = install_state_defaults();
-    $form_state = array();
+    $form_state = new FormState();
     $form_state['build_info']['args'][] = &$install_state;
     $form = $this->container->get('form_builder')
       ->buildForm('Drupal\Core\Installer\Form\SiteConfigureForm', $form_state);
diff --git a/core/modules/user/src/Tests/UserAccountLinksTests.php b/core/modules/user/src/Tests/UserAccountLinksTests.php
index d57e39b..e602120 100644
--- a/core/modules/user/src/Tests/UserAccountLinksTests.php
+++ b/core/modules/user/src/Tests/UserAccountLinksTests.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Tests;
 
+use Drupal\Core\Menu\MenuTreeParameters;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -43,14 +44,14 @@ function testSecondaryMenu() {
     // For a logged-in user, expect the secondary menu to have links for "My
     // account" and "Log out".
     $link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
-      ':menu_class' => 'links',
+      ':menu_class' => 'menu',
       ':href' => 'user',
       ':text' => 'My account',
     ));
     $this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
 
     $link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
-      ':menu_class' => 'links',
+      ':menu_class' => 'menu',
       ':href' => 'user/logout',
       ':text' => 'Log out',
     ));
@@ -61,13 +62,15 @@ function testSecondaryMenu() {
     $this->drupalGet('<front>');
 
     // For a logged-out user, expect no secondary links.
-    /** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
-    $menu_tree = \Drupal::service('menu_link.tree');
-    $tree = $menu_tree->buildTree('account');
+    $menu_tree = \Drupal::menuTree();
+    $tree = $menu_tree->load('account', new MenuTreeParameters());
+    $manipulators = array(
+      array('callable' => 'menu.default_tree_manipulators:checkAccess'),
+    );
+    $tree = $menu_tree->transform($tree, $manipulators);
     $this->assertEqual(count($tree), 1, 'The secondary links menu contains only one menu link.');
-    $link = reset($tree);
-    $link = $link['link'];
-    $this->assertTrue((bool) $link->hidden, 'The menu link is hidden.');
+    $element = reset($tree);
+    $this->assertTrue($element->link->isHidden(), 'The menu link is hidden.');
   }
 
   /**
@@ -80,7 +83,7 @@ function testDisabledAccountLink() {
     // Verify that the 'My account' link exists before we check for its
     // disappearance.
     $link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
-      ':menu_class' => 'links',
+      ':menu_class' => 'menu',
       ':href' => 'user',
       ':text' => 'My account',
     ));
@@ -94,10 +97,7 @@ function testDisabledAccountLink() {
     $this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
 
     // Disable the 'My account' link.
-    $input = $this->xpath('//input[@id=:field_id]/@name', array(':field_id' => (string)$label[0]));
-    $edit = array(
-      (string) $input[0] => FALSE,
-    );
+    $edit['links[menu_plugin_id:user.page][enabled]'] = FALSE;
     $this->drupalPostForm('admin/structure/menu/manage/account', $edit, t('Save'));
 
     // Get the homepage.
@@ -105,7 +105,7 @@ function testDisabledAccountLink() {
 
     // Verify that the 'My account' link does not appear when disabled.
     $link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
-      ':menu_class' => 'links',
+      ':menu_class' => 'menu',
       ':href' => 'user',
       ':text' => 'My account',
     ));
diff --git a/core/modules/user/src/Tests/UserAdminLanguageTest.php b/core/modules/user/src/Tests/UserAdminLanguageTest.php
index be7a6cc..d2b08b7 100644
--- a/core/modules/user/src/Tests/UserAdminLanguageTest.php
+++ b/core/modules/user/src/Tests/UserAdminLanguageTest.php
@@ -36,7 +36,7 @@ class UserAdminLanguageTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('user', 'language');
+  public static $modules = array('user', 'language', 'language_test');
 
   public function setUp() {
     parent::setUp();
@@ -106,16 +106,59 @@ function testUserAdminLanguageConfigurationAvailableIfAdminLanguageNegotiationIs
   }
 
   /**
+   * Tests the actual language negotiation.
+   */
+  function testActualNegotiation() {
+    $this->drupalLogin($this->adminUser);
+    $this->addCustomLanguage();
+    $this->setLanguageNegotiation();
+
+    // Even though we have admin language negotiation, so long as the user has
+    // no preference set, negotiation will fall back further.
+    $path = 'user/' . $this->adminUser->id() . '/edit';
+    $this->drupalGet($path);
+    $this->assertText('Language negotiation method: language-default');
+
+    // Set a preferred language code for the user.
+    $path = 'user/' . $this->adminUser->id() . '/edit';
+    $edit = array();
+    $edit['preferred_admin_langcode'] = 'xx';
+    $this->drupalPostForm($path, $edit, t('Save'));
+
+    // Test negotiation with the URL method first. The admin method will only
+    // be used if the URL method did not match.
+    $path = 'user/' . $this->adminUser->id() . '/edit';
+    $this->drupalGet($path);
+    $this->assertText('Language negotiation method: language-user-admin');
+    $path = 'xx/user/' . $this->adminUser->id() . '/edit';
+    $this->drupalGet($path);
+    $this->assertText('Language negotiation method: language-url');
+
+    // Test negotiation with the admin language method first. The admin method
+    // will be used at all times.
+    $this->setLanguageNegotiation(TRUE);
+    $path = 'user/' . $this->adminUser->id() . '/edit';
+    $this->drupalGet($path);
+    $this->assertText('Language negotiation method: language-user-admin');
+    $path = 'xx/user/' . $this->adminUser->id() . '/edit';
+    $this->drupalGet($path);
+    $this->assertText('Language negotiation method: language-user-admin');
+  }
+
+  /**
    * Sets the User interface negotiation detection method.
    *
+   * @param bool $admin_first
+   *   Whether the admin negotiation should be first.
+   *
    * Enables the "Account preference for administration pages" language
    * detection method for the User interface language negotiation type.
    */
-  function setLanguageNegotiation() {
+  function setLanguageNegotiation($admin_first = FALSE) {
     $edit = array(
       'language_interface[enabled][language-user-admin]' => TRUE,
       'language_interface[enabled][language-url]' => TRUE,
-      'language_interface[weight][language-user-admin]' => -8,
+      'language_interface[weight][language-user-admin]' => ($admin_first ? -12 : -8),
       'language_interface[weight][language-url]' => -10,
     );
     $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
diff --git a/core/modules/user/src/Tests/Views/ArgumentValidateTest.php b/core/modules/user/src/Tests/Views/ArgumentValidateTest.php
index f1e9c0e..04c8b0a 100644
--- a/core/modules/user/src/Tests/Views/ArgumentValidateTest.php
+++ b/core/modules/user/src/Tests/Views/ArgumentValidateTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Tests\Views;
 
+use Drupal\Core\Form\FormState;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
 use Drupal\views\Views;
 
@@ -45,7 +46,8 @@ function testArgumentValidateUserUid() {
     // Fail for a valid numeric, but for a user that doesn't exist
     $this->assertFalse($view->argument['null']->validateArgument(32));
 
-    $form = $form_state = array();
+    $form = array();
+    $form_state = new FormState();
     $view->argument['null']->buildOptionsForm($form, $form_state);
     $sanitized_id = ArgumentPluginBase::encodeValidatorId('entity:user');
     $this->assertTrue($form['validate']['options'][$sanitized_id]['roles']['#states']['visible'][':input[name="options[validate][options][' . $sanitized_id . '][restrict_roles]"]']['checked']);
diff --git a/core/modules/user/tests/modules/user_form_test/src/Form/TestCurrentPassword.php b/core/modules/user/tests/modules/user_form_test/src/Form/TestCurrentPassword.php
index 1acbea5..b01fc79 100644
--- a/core/modules/user/tests/modules/user_form_test/src/Form/TestCurrentPassword.php
+++ b/core/modules/user/tests/modules/user_form_test/src/Form/TestCurrentPassword.php
@@ -8,6 +8,7 @@
 namespace Drupal\user_form_test\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\UserInterface;
 
 /**
@@ -28,7 +29,7 @@ public function getFormId() {
    * @param \Drupal\user\Entity\UserInterface $user
    *   The user account.
    */
-  public function buildForm(array $form, array &$form_state, UserInterface $user = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, UserInterface $user = NULL) {
     $form_state['user'] = $user ;
     $form['user_form_test_field'] = array(
       '#type' => 'textfield',
@@ -60,7 +61,7 @@ public function buildForm(array $form, array &$form_state, UserInterface $user =
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The password has been validated and the form submitted successfully.'));
   }
 
diff --git a/core/modules/user/user.links.menu.yml b/core/modules/user/user.links.menu.yml
index bc421f0..3490a8d 100644
--- a/core/modules/user/user.links.menu.yml
+++ b/core/modules/user/user.links.menu.yml
@@ -3,6 +3,7 @@ user.page:
   weight: -10
   route_name: user.page
   menu_name: account
+  class: Drupal\user\Plugin\Menu\MyAccountMenuLink
 user.logout:
   title: 'Log out'
   route_name: user.logout
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 2253d1c..c23cc2c 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -4,6 +4,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
@@ -482,7 +483,7 @@ function user_user_view(array &$build, UserInterface $account, EntityViewDisplay
 /**
  * Sets the value of the user register and profile forms' langcode element.
  */
-function _user_language_selector_langcode_value($element, $input, &$form_state) {
+function _user_language_selector_langcode_value($element, $input, FormStateInterface $form_state) {
   // Only add to the description if the form element have a description.
   if (isset($form_state['complete_form']['language']['preferred_langcode']['#description'])) {
     $form_state['complete_form']['language']['preferred_langcode']['#description'] .= ' ' . t("This is also assumed to be the primary language of this account's profile information.");
@@ -495,7 +496,7 @@ function _user_language_selector_langcode_value($element, $input, &$form_state)
  *
  * @see AccountForm::form()
  */
-function user_validate_current_pass(&$form, &$form_state) {
+function user_validate_current_pass(&$form, FormStateInterface $form_state) {
   $account = $form_state['user'];
   foreach ($form_state['values']['current_pass_required_values'] as $key => $name) {
     // This validation only works for required textfields (like mail) or
@@ -634,19 +635,6 @@ function template_preprocess_username(&$variables) {
 }
 
 /**
- * Implements hook_menu_link_presave().
- */
-function user_menu_link_presave(MenuLink $menu_link) {
-  // The path 'user' must be accessible for anonymous users, but only visible
-  // for authenticated users. Authenticated users should see "My account", but
-  // anonymous users should not see it at all. Therefore, invoke
-  // user_menu_link_load() to conditionally hide the link.
-  if ($menu_link->machine_name == 'user.page') {
-    $menu_link->options['alter'] = TRUE;
-  }
-}
-
-/**
  * Implements hook_menu_breadcrumb_alter().
  */
 function user_menu_breadcrumb_alter(&$active_trail, $item) {
@@ -658,16 +646,6 @@ function user_menu_breadcrumb_alter(&$active_trail, $item) {
 }
 
 /**
- * Implements hook_translated_menu_link_alter().
- */
-function user_translated_menu_link_alter(MenuLink &$menu_link) {
-  // Hide the "User account" link for anonymous users.
-  if ($menu_link->machine_name == 'user.page' && \Drupal::currentUser()->isAnonymous()) {
-    $menu_link->hidden = 1;
-  }
-}
-
-/**
  * Finalizes the login process and logs in a user.
  *
  * The function logs in the user, records a watchdog message about the new
diff --git a/core/modules/views/config/schema/views.schema.yml b/core/modules/views/config/schema/views.schema.yml
index 8b837c2..c110e44 100644
--- a/core/modules/views/config/schema/views.schema.yml
+++ b/core/modules/views/config/schema/views.schema.yml
@@ -115,5 +115,8 @@ views.view.*:
             position:
               type: integer
               label: 'Position'
+            provider:
+              type: string
+              label: 'Display provider module'
             display_options:
               type: views.display.[%parent.display_plugin]
diff --git a/core/modules/views/includes/ajax.inc b/core/modules/views/includes/ajax.inc
index 84c33eb..5930856 100644
--- a/core/modules/views/includes/ajax.inc
+++ b/core/modules/views/includes/ajax.inc
@@ -5,6 +5,7 @@
  * Handles the server side AJAX interactions of Views.
  */
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Ajax\HighlightCommand;
 use Drupal\Core\Ajax\OpenModalDialogCommand;
 use Drupal\Core\Ajax\AjaxResponse;
@@ -14,16 +15,14 @@
  * some AJAX stuff automatically.
  * This makes some assumptions about the client.
  */
-function views_ajax_form_wrapper($form_class, &$form_state) {
+function views_ajax_form_wrapper($form_class, FormStateInterface &$form_state) {
   // This won't override settings already in.
-  $form_state += array(
-    'rerender' => FALSE,
-    'no_redirect' => !empty($form_state['ajax']),
-    'no_cache' => TRUE,
-    'build_info' => array(
-      'args' => array(),
-    ),
-  );
+  $form_state->setIfNotExists('rerender', FALSE);
+  $form_state->setIfNotExists('no_redirect', !empty($form_state['ajax']));
+  $form_state->setIfNotExists('no_cache', TRUE);
+  $form_state->setIfNotExists('build_info', array(
+    'args' => array(),
+  ));
 
   $form = \Drupal::formBuilder()->buildForm($form_class, $form_state);
   $output = drupal_render($form);
diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php
index 93c446c..0f783ff 100644
--- a/core/modules/views/src/Entity/View.php
+++ b/core/modules/views/src/Entity/View.php
@@ -263,6 +263,11 @@ public function calculateDependencies() {
       $handler_types[] = $type['plural'];
     }
     foreach ($this->get('display') as $display) {
+      // Add dependency for the display itself.
+      if (isset($display['provider'])) {
+        $this->addDependency('module', $display['provider']);
+      }
+
       // Collect all dependencies of all handlers.
       foreach ($handler_types as $handler_type) {
         if (!empty($display['display_options'][$handler_type])) {
diff --git a/core/modules/views/src/Form/ViewsExposedForm.php b/core/modules/views/src/Form/ViewsExposedForm.php
index ae3da03..2c78f5f 100644
--- a/core/modules/views/src/Form/ViewsExposedForm.php
+++ b/core/modules/views/src/Form/ViewsExposedForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ExposedFormCache;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -51,7 +52,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     // Don't show the form when batch operations are in progress.
     if ($batch = batch_get() && isset($batch['current_set'])) {
       return array(
@@ -131,7 +132,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     foreach (array('field', 'filter') as $type) {
       /** @var \Drupal\views\Plugin\views\HandlerBase[] $handlers */
       $handlers = &$form_state['view']->$type;
@@ -147,7 +148,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     foreach (array('field', 'filter') as $type) {
       /** @var \Drupal\views\Plugin\views\HandlerBase[] $handlers */
       $handlers = &$form_state['view']->$type;
diff --git a/core/modules/views/src/Form/ViewsForm.php b/core/modules/views/src/Form/ViewsForm.php
index 02bf7cb..ac88a11 100644
--- a/core/modules/views/src/Form/ViewsForm.php
+++ b/core/modules/views/src/Form/ViewsForm.php
@@ -13,6 +13,7 @@
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\views\ViewExecutable;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -115,7 +116,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, ViewExecutable $view = NULL, $output = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = NULL) {
     $form_state['step'] = isset($form_state['step']) ? $form_state['step'] : 'views_form_views_form';
     $form_state['step_controller']['views_form_views_form'] = 'Drupal\views\Form\ViewsFormMainForm';
 
@@ -146,7 +147,7 @@ public function buildForm(array $form, array &$form_state, ViewExecutable $view
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_object = $this->getFormObject($form_state);
     $form_object->validateForm($form, $form_state);
   }
@@ -154,7 +155,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_object = $this->getFormObject($form_state);
     $form_object->submitForm($form, $form_state);
   }
@@ -162,13 +163,13 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Returns the object used to build the step form.
    *
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form_state of the current form.
    *
    * @return \Drupal\Core\Form\FormInterface
    *   The form object to use.
    */
-  protected function getFormObject(array $form_state) {
+  protected function getFormObject($form_state) {
     // If this is a class, instantiate it.
     $form_step_class = isset($form_state['step_controller'][$form_state['step']]) ? $form_state['step_controller'][$form_state['step']] : 'Drupal\views\Form\ViewsFormMainForm';
     return $this->classResolver->getInstanceFromDefinition($form_step_class);
diff --git a/core/modules/views/src/Form/ViewsFormMainForm.php b/core/modules/views/src/Form/ViewsFormMainForm.php
index 98cdc4f..6c48b7e 100644
--- a/core/modules/views/src/Form/ViewsFormMainForm.php
+++ b/core/modules/views/src/Form/ViewsFormMainForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Form;
 
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 
 class ViewsFormMainForm implements FormInterface {
@@ -21,7 +22,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, ViewExecutable $view = NULL, $output = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = NULL) {
     $form['#prefix'] = '<div class="views-form">';
     $form['#suffix'] = '</div>';
     $form['#theme'] = 'form';
@@ -106,7 +107,7 @@ public function buildForm(array $form, array &$form_state, ViewExecutable $view
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $view = $form_state['build_info']['args'][0];
 
     // Call the validation method on every field handler that has it.
@@ -129,7 +130,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $view = $form_state['build_info']['args'][0];
 
     // Call the submit method on every field handler that has it.
diff --git a/core/modules/views/src/ManyToOneHelper.php b/core/modules/views/src/ManyToOneHelper.php
index 4c4d2ae..12bfc35 100644
--- a/core/modules/views/src/ManyToOneHelper.php
+++ b/core/modules/views/src/ManyToOneHelper.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\HandlerBase;
 
 /**
@@ -33,7 +34,7 @@ public static function defineOptions(&$options) {
     $options['reduce_duplicates'] = array('default' => FALSE, 'bool' => TRUE);
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['reduce_duplicates'] = array(
       '#type' => 'checkbox',
       '#title' => t('Reduce duplicates'),
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlock.php b/core/modules/views/src/Plugin/Block/ViewsBlock.php
index a80aa97..9e5bc99 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlock.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Config\Entity\Query\Query;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -78,7 +79,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function blockForm($form, &$form_state) {
+  public function blockForm($form, FormStateInterface $form_state) {
     if ($this->displaySet) {
       return $this->view->display_handler->blockForm($this, $form, $form_state);
     }
@@ -89,7 +90,7 @@ public function blockForm($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockValidate($form, &$form_state) {
+  public function blockValidate($form, FormStateInterface $form_state) {
     if ($this->displaySet) {
       $this->view->display_handler->blockValidate($this, $form, $form_state);
     }
@@ -98,7 +99,7 @@ public function blockValidate($form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     parent::blockSubmit($form, $form_state);
     if ($this->displaySet) {
       $this->view->display_handler->blockSubmit($this, $form, $form_state);
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlockBase.php b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
index 5a63e76..1d4dd98 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\Block;
 
 use Drupal\block\BlockBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\views\ViewExecutableFactory;
 use Drupal\Core\Entity\EntityStorageInterface;
@@ -105,7 +106,7 @@ public function defaultConfiguration() {
   /**
    * {@inheritdoc}
    */
-  public function buildConfigurationForm(array $form, array &$form_state) {
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
     // Set the default label to '' so the views internal title is used.
@@ -163,7 +164,7 @@ public function buildConfigurationForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function blockSubmit($form, &$form_state) {
+  public function blockSubmit($form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['views_label_checkbox'])) {
       $this->configuration['views_label'] = $form_state['values']['views_label'];
     }
diff --git a/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php b/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php
new file mode 100644
index 0000000..e83af2b
--- /dev/null
+++ b/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\Derivative\ViewsMenuLink.
+ */
+
+namespace Drupal\views\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DeriverInterface;
+use Drupal\views\Views;
+
+/**
+ * Provides menu links for Views.
+ *
+ * @see \Drupal\views\Plugin\Menu\ViewsMenuLink
+ */
+class ViewsMenuLink implements DeriverInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
+    if (!isset($this->derivatives)) {
+      $this->getDerivativeDefinitions($base_plugin_definition);
+    }
+    if (isset($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $links = array();
+    // @todo Replace uses_hook_menu with an annotation.
+    //   https://www.drupal.org/node/2310371
+    $views = Views::getApplicableViews('uses_hook_menu');
+    foreach ($views as $data) {
+      /** @var \Drupal\views\ViewExecutable $view */
+      list($view, $display_id) = $data;
+      if ($result = $view->getMenuLinks($display_id)) {
+        foreach ($result as $link_id => $link) {
+          $links[$link_id] = $link + $base_plugin_definition;
+        }
+      }
+    }
+
+    return $links;
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php b/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php
new file mode 100644
index 0000000..e1dc003
--- /dev/null
+++ b/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\Menu\Form\ViewsMenuLinkForm.
+ */
+
+namespace Drupal\views\Plugin\Menu\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Menu\Form\MenuLinkDefaultForm;
+
+/**
+ * Provides a form to edit Views menu links.
+ *
+ * This provides the feature to edit the title and description, in contrast to
+ * the default menu link form.
+ *
+ * @see \Drupal\views\Plugin\Menu\ViewsMenuLink
+ */
+class ViewsMenuLinkForm extends MenuLinkDefaultForm {
+
+  /**
+   * The edited views menu link.
+   *
+   * @var \Drupal\views\Plugin\Menu\ViewsMenuLink
+   */
+  protected $menuLink;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+
+    // Put the title field first.
+    $form['title'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Title'),
+      // @todo Ensure that the view is not loaded with a localized title.
+      //   https://www.drupal.org/node/2309507
+      '#default_value' => $this->menuLink->getTitle(),
+      '#weight' => -10,
+    );
+
+    $form['description'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Description'),
+      '#description' => $this->t('Shown when hovering over the menu link.'),
+      // @todo Ensure that the view is not loaded with a localized description.
+      //   https://www.drupal.org/node/2309507
+      '#default_value' => $this->menuLink->getDescription(),
+      '#weight' => -5,
+    );
+
+    $form += parent::buildConfigurationForm($form, $form_state);
+
+    $form['info']['#weight'] = -8;
+    $form['path']['#weight'] = -7;
+
+    $view = $this->menuLink->loadView();
+    $id = $view->storage->id();
+    $label = $view->storage->label();
+    if ($this->moduleHandler->moduleExists('views_ui')) {
+      $message = $this->t('This link is provided by the Views module. The path can be changed by editing the view <a href="@url">@label</a>', array('@url' => \Drupal::url('views_ui.edit', array('view' => $id)), '@label' => $label));
+    }
+    else {
+      $message = $this->t('This link is provided by the Views module from view %label.', array('%label' => $label));
+    }
+    $form['info']['#title'] = $message;
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function extractFormValues(array &$form, FormStateInterface $form_state) {
+    $definition = parent::extractFormValues($form, $form_state);
+    $definition['title'] = $form_state['values']['title'];
+    $definition['description'] = $form_state['values']['description'];
+
+    return $definition;
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php
new file mode 100644
index 0000000..4e164d7
--- /dev/null
+++ b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php
@@ -0,0 +1,157 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\Menu\ViewsMenuLink.
+ */
+
+namespace Drupal\views\Plugin\Menu;
+
+use Drupal\Core\Menu\MenuLinkBase;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\views\ViewExecutableFactory;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines menu links provided by views.
+ *
+ * @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
+ */
+class ViewsMenuLink extends MenuLinkBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $overrideAllowed = array(
+    'menu_name' => 1,
+    'parent' => 1,
+    'weight' => 1,
+    'expanded' => 1,
+    'hidden' => 1,
+    'title' => 1,
+    'description' => 1,
+    'metadata' => 1,
+  );
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * The view executable factory.
+   *
+   * @var \Drupal\views\ViewExecutableFactory
+   */
+  protected $viewExecutableFactory;
+
+  /**
+   * The view executable of the menu link.
+   *
+   * @var \Drupal\views\ViewExecutable
+   */
+  protected $view;
+
+  /**
+   * Constructs a new ViewsMenuLink.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager
+   * @param \Drupal\views\ViewExecutableFactory $view_executable_factory
+   *   The view executable factory
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ViewExecutableFactory $view_executable_factory) {
+    $this->configuration = $configuration;
+    $this->pluginId = $plugin_id;
+    $this->pluginDefinition = $plugin_definition;
+
+    $this->entityManager = $entity_manager;
+    $this->viewExecutableFactory = $view_executable_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.manager'),
+      $container->get('views.executable')
+    );
+  }
+
+  /**
+   * Initializes the proper view.
+   *
+   * @return \Drupal\views\ViewExecutable
+   *   The view executable.
+   */
+  public function loadView() {
+    if (empty($this->view)) {
+      $metadata = $this->getMetaData();
+      $view_id = $metadata['view_id'];
+      $display_id = $metadata['display_id'];
+      $view_entity = $this->entityManager->getStorage('view')->load($view_id);
+      $view = $this->viewExecutableFactory->get($view_entity);
+      $view->setDisplay($display_id);
+      $view->initDisplay();
+      $this->view = $view;
+    }
+    return $this->view;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTitle() {
+    // @todo Get the translated value from the config without instantiating the
+    //   view. https://www.drupal.org/node/2310379
+    return $this->loadView()->display_handler->getOption('menu')['title'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->loadView()->display_handler->getOption('menu')['description'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function updateLink(array $new_definition_values, $persist) {
+    $overrides = array_intersect_key($new_definition_values, $this->overrideAllowed);
+    if ($persist) {
+      $view = $this->loadView();
+      $display = &$view->storage->getDisplay($view->current_display);
+      // Just save the title to the original view.
+      $changed = FALSE;
+      foreach (array('title' => 'title', 'weight' => 'weight', 'menu' => 'name', 'description' => 'description') as $definition_key => $views_key) {
+        if ($display['display_options']['menu'][$views_key] != $new_definition_values[$definition_key]) {
+          $display['display_options']['menu'][$views_key] = $new_definition_values[$definition_key];
+          $changed = TRUE;
+        }
+      }
+      if ($changed) {
+        // @todo Improve this to not trigger a full rebuild of everything, if we
+        //   just changed some properties. https://www.drupal.org/node/2310389
+        $view->storage->save();
+      }
+    }
+    // Update the definition.
+    $this->pluginDefinition = $overrides + $this->pluginDefinition;
+    return $this->pluginDefinition;
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/entity_reference/selection/ViewsSelection.php b/core/modules/views/src/Plugin/entity_reference/selection/ViewsSelection.php
index aa84db2..aa8294a 100644
--- a/core/modules/views/src/Plugin/entity_reference/selection/ViewsSelection.php
+++ b/core/modules/views/src/Plugin/entity_reference/selection/ViewsSelection.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface;
 use Drupal\views\Views;
 
@@ -203,7 +204,7 @@ public function validateReferenceableEntities(array $ids) {
   /**
    * {@inheritdoc}
    */
-  public function validateAutocompleteInput($input, &$element, &$form_state, $form, $strict = TRUE) {
+  public function validateAutocompleteInput($input, &$element, FormStateInterface $form_state, $form, $strict = TRUE) {
     return NULL;
   }
 
@@ -215,7 +216,7 @@ public function entityQueryAlter(SelectInterface $query) {}
   /**
    * Element validate; Check View is valid.
    */
-  public function settingsFormValidate($element, &$form_state, $form) {
+  public function settingsFormValidate($element, FormStateInterface $form_state, $form) {
     // Split view name and display name from the 'view_and_display' value.
     if (!empty($element['view_and_display']['#value'])) {
       list($view, $display) = explode(':', $element['view_and_display']['#value']);
diff --git a/core/modules/views/src/Plugin/views/BrokenHandlerTrait.php b/core/modules/views/src/Plugin/views/BrokenHandlerTrait.php
index 2135813..4bd9948 100644
--- a/core/modules/views/src/Plugin/views/BrokenHandlerTrait.php
+++ b/core/modules/views/src/Plugin/views/BrokenHandlerTrait.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * A Trait for Views broken handlers.
  */
@@ -55,7 +57,7 @@ public function query($group_by = FALSE) {
    *
    * @see \Drupal\views\Plugin\views\PluginBase::defineOptions().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $description_top = t('The handler for this item is broken or missing. The following details are available:');
 
     $items = array(
diff --git a/core/modules/views/src/Plugin/views/HandlerBase.php b/core/modules/views/src/Plugin/views/HandlerBase.php
index e53cf75..368b4ac 100644
--- a/core/modules/views/src/Plugin/views/HandlerBase.php
+++ b/core/modules/views/src/Plugin/views/HandlerBase.php
@@ -12,6 +12,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -278,7 +279,7 @@ protected function caseTransform($string, $option) {
   /**
    * Build the options form.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // Some form elements belong in a fieldset for presentation, but can't
     // be moved into one because of the form_state['values'] hierarchy. Those
     // elements can add a #fieldset => 'fieldset_name' property, and they'll
@@ -349,7 +350,7 @@ public function usesGroupBy() {
   /**
    * Provide a form for aggregation settings.
    */
-  public function buildGroupByForm(&$form, &$form_state) {
+  public function buildGroupByForm(&$form, FormStateInterface $form_state) {
     $display_id = $form_state['display_id'];
     $type = $form_state['type'];
     $id = $form_state['id'];
@@ -375,7 +376,7 @@ public function buildGroupByForm(&$form, &$form_state) {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitGroupByForm(&$form, &$form_state) {
+  public function submitGroupByForm(&$form, FormStateInterface $form_state) {
     $form_state['handler']->options['group_type'] = $form_state['values']['options']['group_type'];
   }
 
@@ -393,18 +394,18 @@ public function defineExtraOptions(&$option) { }
   /**
    * Provide a form for setting options.
    */
-  public function buildExtraOptionsForm(&$form, &$form_state) { }
+  public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Validate the options form.
    */
-  public function validateExtraOptionsForm($form, &$form_state) { }
+  public function validateExtraOptionsForm($form, FormStateInterface $form_state) { }
 
   /**
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitExtraOptionsForm($form, &$form_state) { }
+  public function submitExtraOptionsForm($form, FormStateInterface $form_state) { }
 
   /**
    * Determine if a handler can be exposed.
@@ -425,43 +426,43 @@ public function exposedInfo() { }
   /**
    * Render our chunk of the exposed handler form when selecting
    */
-  public function buildExposedForm(&$form, &$form_state) { }
+  public function buildExposedForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Validate the exposed handler form
    */
-  public function validateExposed(&$form, &$form_state) { }
+  public function validateExposed(&$form, FormStateInterface $form_state) { }
 
   /**
    * Submit the exposed handler form
    */
-  public function submitExposed(&$form, &$form_state) { }
+  public function submitExposed(&$form, FormStateInterface $form_state) { }
 
   /**
    * Form for exposed handler options.
    */
-  public function buildExposeForm(&$form, &$form_state) { }
+  public function buildExposeForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Validate the options form.
    */
-  public function validateExposeForm($form, &$form_state) { }
+  public function validateExposeForm($form, FormStateInterface $form_state) { }
 
   /**
    * Perform any necessary changes to the form exposes prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitExposeForm($form, &$form_state) { }
+  public function submitExposeForm($form, FormStateInterface $form_state) { }
 
   /**
    * Shortcut to display the expose/hide button.
    */
-  public function showExposeButton(&$form, &$form_state) { }
+  public function showExposeButton(&$form, FormStateInterface $form_state) { }
 
   /**
    * Shortcut to display the exposed options form.
    */
-  public function showExposeForm(&$form, &$form_state) {
+  public function showExposeForm(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed'])) {
       return;
     }
@@ -887,7 +888,7 @@ public static function breakPhraseString($str, &$handler = NULL) {
   /**
    * Displays the Expose form.
    */
-  public function displayExposedForm($form, &$form_state) {
+  public function displayExposedForm($form, FormStateInterface $form_state) {
     $item = &$this->options;
     // flip
     $item['exposed'] = empty($item['exposed']);
@@ -911,7 +912,7 @@ public function displayExposedForm($form, &$form_state) {
    * A submit handler that is used for storing temporary items when using
    * multi-step changes, such as ajax requests.
    */
-  public function submitTemporaryForm($form, &$form_state) {
+  public function submitTemporaryForm($form, FormStateInterface $form_state) {
     // Run it through the handler's submit function.
     $this->submitOptionsForm($form['options'], $form_state);
     $item = $this->options;
diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php
index f19520a..c2a4869 100644
--- a/core/modules/views/src/Plugin/views/PluginBase.php
+++ b/core/modules/views/src/Plugin/views/PluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase as ComponentPluginBase;
 use Drupal\Core\Render\Element;
@@ -216,7 +217,7 @@ public function destroy() {
   /**
    * Provide a form to edit options for this plugin.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // Some form elements belong in a fieldset for presentation, but can't
     // be moved into one because of the form_state['values'] hierarchy. Those
     // elements can add a #fieldset => 'fieldset_name' property, and they'll
@@ -227,12 +228,12 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Validate the options form.
    */
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Handle any special handling on the validate form.
    */
-  public function submitOptionsForm(&$form, &$form_state) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Add anything to the query that we might need to.
@@ -336,10 +337,10 @@ public function getAvailableGlobalTokens($prepared = FALSE, array $types = array
    *
    * @param array $form
    *   The form array to alter, passed by reference.
-   * @param array $form_state
-   *   The form state array to alter, passed by reference.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function globalTokenForm(&$form, &$form_state) {
+  public function globalTokenForm(&$form, FormStateInterface $form_state) {
     $token_items = array();
 
     foreach ($this->getAvailableGlobalTokens() as $type => $tokens) {
diff --git a/core/modules/views/src/Plugin/views/area/AreaPluginBase.php b/core/modules/views/src/Plugin/views/area/AreaPluginBase.php
index 12d1a48..54a11bf 100644
--- a/core/modules/views/src/Plugin/views/area/AreaPluginBase.php
+++ b/core/modules/views/src/Plugin/views/area/AreaPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\HandlerBase;
@@ -81,7 +82,7 @@ public function adminSummary() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     if ($form_state['type'] != 'empty') {
diff --git a/core/modules/views/src/Plugin/views/area/Entity.php b/core/modules/views/src/Plugin/views/area/Entity.php
index f762c03..1cb3f1e 100644
--- a/core/modules/views/src/Plugin/views/area/Entity.php
+++ b/core/modules/views/src/Plugin/views/area/Entity.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
 
@@ -54,7 +55,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['view_mode'] = array(
diff --git a/core/modules/views/src/Plugin/views/area/HTTPStatusCode.php b/core/modules/views/src/Plugin/views/area/HTTPStatusCode.php
index 1118169..79d395e 100644
--- a/core/modules/views/src/Plugin/views/area/HTTPStatusCode.php
+++ b/core/modules/views/src/Plugin/views/area/HTTPStatusCode.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
@@ -32,7 +33,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Get all possible status codes defined by symfony.
diff --git a/core/modules/views/src/Plugin/views/area/Result.php b/core/modules/views/src/Plugin/views/area/Result.php
index c675ed6..db596a7 100644
--- a/core/modules/views/src/Plugin/views/area/Result.php
+++ b/core/modules/views/src/Plugin/views/area/Result.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\style\DefaultSummary;
 
 /**
@@ -37,7 +38,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $item_list = array(
       '#theme' => 'item_list',
diff --git a/core/modules/views/src/Plugin/views/area/Text.php b/core/modules/views/src/Plugin/views/area/Text.php
index de89210..5a137c5 100644
--- a/core/modules/views/src/Plugin/views/area/Text.php
+++ b/core/modules/views/src/Plugin/views/area/Text.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Views area text handler.
  *
@@ -29,7 +31,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['content'] = array(
@@ -45,7 +47,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     $form_state['values']['options']['format'] = $form_state['values']['options']['content']['format'];
     $form_state['values']['options']['content'] = $form_state['values']['options']['content']['value'];
     parent::submitOptionsForm($form, $form_state);
diff --git a/core/modules/views/src/Plugin/views/area/TextCustom.php b/core/modules/views/src/Plugin/views/area/TextCustom.php
index fcd798c..5f6a63d 100644
--- a/core/modules/views/src/Plugin/views/area/TextCustom.php
+++ b/core/modules/views/src/Plugin/views/area/TextCustom.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Views area text handler.
  *
@@ -28,7 +30,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['content'] = array(
diff --git a/core/modules/views/src/Plugin/views/area/Title.php b/core/modules/views/src/Plugin/views/area/Title.php
index ef29f3f..bf4eaa0 100644
--- a/core/modules/views/src/Plugin/views/area/Title.php
+++ b/core/modules/views/src/Plugin/views/area/Title.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
 use \Drupal\Core\Utility\Title as UtilityTitle;
 
 /**
@@ -30,7 +31,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['title'] = array(
diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
index 6f0add5..9cf0988 100644
--- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
+++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Tokenized base class for area handlers.
  *
@@ -31,7 +33,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Add tokenization form elements.
@@ -41,7 +43,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Adds tokenization form elements.
    */
-  public function tokenForm(&$form, &$form_state) {
+  public function tokenForm(&$form, FormStateInterface $form_state) {
     $form['tokenize'] = array(
       '#type' => 'checkbox',
       '#title' => t('Use replacement tokens from the first row'),
diff --git a/core/modules/views/src/Plugin/views/area/View.php b/core/modules/views/src/Plugin/views/area/View.php
index a0ec508..19650fe 100644
--- a/core/modules/views/src/Plugin/views/area/View.php
+++ b/core/modules/views/src/Plugin/views/area/View.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\area;
 
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -78,7 +79,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $view_display = $this->view->storage->id() . ':' . $this->view->current_display;
diff --git a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
index a253a6b..3a8bf48 100644
--- a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\argument;
 
 use Drupal\Component\Utility\String as UtilityString;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -150,7 +151,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $argument_text = $this->view->display_handler->getArgumentText();
@@ -343,7 +344,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     if (empty($form_state['values']['options'])) {
       return;
     }
@@ -372,7 +373,7 @@ public function validateOptionsForm(&$form, &$form_state) {
 
   }
 
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     if (empty($form_state['values']['options'])) {
       return;
     }
@@ -473,7 +474,7 @@ protected function defaultActions($which = NULL) {
    * Provide a form for selecting the default argument when the
    * default action is set to provide default argument.
    */
-  public function defaultArgumentForm(&$form, &$form_state) {
+  public function defaultArgumentForm(&$form, FormStateInterface $form_state) {
     $plugins = Views::pluginManager('argument_default')->getDefinitions();
     $options = array();
 
@@ -538,7 +539,7 @@ public function defaultArgumentForm(&$form, &$form_state) {
    * Provide a form for selecting further summary options when the
    * default action is set to display one.
    */
-  public function defaultSummaryForm(&$form, &$form_state) {
+  public function defaultSummaryForm(&$form, FormStateInterface $form_state) {
     $style_plugins = Views::pluginManager('style')->getDefinitions();
     $summary_plugins = array();
     $format_options = array();
diff --git a/core/modules/views/src/Plugin/views/argument/Date.php b/core/modules/views/src/Plugin/views/argument/Date.php
index 67c0055..3a3db7f 100644
--- a/core/modules/views/src/Plugin/views/argument/Date.php
+++ b/core/modules/views/src/Plugin/views/argument/Date.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\argument;
 
 use Drupal\Core\Database\Database;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -49,7 +50,7 @@ class Date extends Formula {
   /**
    * Add an option to set the default value to the current date.
    */
-  public function defaultArgumentForm(&$form, &$form_state) {
+  public function defaultArgumentForm(&$form, FormStateInterface $form_state) {
     parent::defaultArgumentForm($form, $form_state);
     $form['default_argument_type']['#options'] += array('date' => $this->t('Current date'));
     $form['default_argument_type']['#options'] += array('node_created' => $this->t("Current node's creation time"));
diff --git a/core/modules/views/src/Plugin/views/argument/ManyToOne.php b/core/modules/views/src/Plugin/views/argument/ManyToOne.php
index 3180862..4e30426 100644
--- a/core/modules/views/src/Plugin/views/argument/ManyToOne.php
+++ b/core/modules/views/src/Plugin/views/argument/ManyToOne.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\argument;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ManyToOneHelper;
@@ -62,7 +63,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // allow + for or, , for and
diff --git a/core/modules/views/src/Plugin/views/argument/Null.php b/core/modules/views/src/Plugin/views/argument/Null.php
index e4fdab6..3c2e758 100644
--- a/core/modules/views/src/Plugin/views/argument/Null.php
+++ b/core/modules/views/src/Plugin/views/argument/Null.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\argument;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Argument handler that ignores the argument.
  *
@@ -26,7 +28,7 @@ protected function defineOptions() {
    * Override buildOptionsForm() so that only the relevant options
    * are displayed to the user.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['must_not_be'] = array(
       '#type' => 'checkbox',
diff --git a/core/modules/views/src/Plugin/views/argument/Numeric.php b/core/modules/views/src/Plugin/views/argument/Numeric.php
index 565b285..951ce65 100644
--- a/core/modules/views/src/Plugin/views/argument/Numeric.php
+++ b/core/modules/views/src/Plugin/views/argument/Numeric.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\argument;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Basic argument handler for arguments that are numeric. Incorporates
  * break_phrase.
@@ -38,7 +40,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // allow + for or, , for and
diff --git a/core/modules/views/src/Plugin/views/argument/String.php b/core/modules/views/src/Plugin/views/argument/String.php
index b606de7..3f92185 100644
--- a/core/modules/views/src/Plugin/views/argument/String.php
+++ b/core/modules/views/src/Plugin/views/argument/String.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\argument;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ManyToOneHelper;
@@ -54,7 +55,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['glossary'] = array(
diff --git a/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php b/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php
index 500e642..13330b3 100644
--- a/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
 use Drupal\views\Plugin\views\PluginBase;
@@ -68,17 +69,17 @@ protected function defineOptions() { return array(); }
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) { }
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Provide the default form form for validating options
    */
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Provide the default form form for submitting options
    */
-  public function submitOptionsForm(&$form, &$form_state, &$options = array()) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = array()) { }
 
   /**
    * Determine if the administrator has the privileges to use this
diff --git a/core/modules/views/src/Plugin/views/argument_default/Fixed.php b/core/modules/views/src/Plugin/views/argument_default/Fixed.php
index 4dcb180..68f3d93 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Fixed.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Fixed.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * The fixed argument default handler.
  *
@@ -26,7 +28,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['argument'] = array(
       '#type' => 'textfield',
diff --git a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
index d8eb1ab..82bf1fa 100644
--- a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
+++ b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * A query parameter argument default handler.
  *
@@ -34,7 +36,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['query_param'] = array(
       '#type' => 'textfield',
diff --git a/core/modules/views/src/Plugin/views/argument_default/Raw.php b/core/modules/views/src/Plugin/views/argument_default/Raw.php
index afbd7af..022d029 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Raw.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Raw.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\argument_default;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Path\AliasManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -68,7 +69,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['index'] = array(
       '#type' => 'select',
diff --git a/core/modules/views/src/Plugin/views/argument_validator/ArgumentValidatorPluginBase.php b/core/modules/views/src/Plugin/views/argument_validator/ArgumentValidatorPluginBase.php
index 655bc2a..875c6fd 100644
--- a/core/modules/views/src/Plugin/views/argument_validator/ArgumentValidatorPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument_validator/ArgumentValidatorPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\argument_validator;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
 use Drupal\views\Plugin\views\PluginBase;
@@ -64,17 +65,17 @@ protected function defineOptions() { return array(); }
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) { }
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Provide the default form form for validating options
    */
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Provide the default form form for submitting options
    */
-  public function submitOptionsForm(&$form, &$form_state, &$options = array()) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = array()) { }
 
   /**
    * Determine if the administrator has the privileges to use this plugin
diff --git a/core/modules/views/src/Plugin/views/argument_validator/Entity.php b/core/modules/views/src/Plugin/views/argument_validator/Entity.php
index a807cbc..fc5f879 100644
--- a/core/modules/views/src/Plugin/views/argument_validator/Entity.php
+++ b/core/modules/views/src/Plugin/views/argument_validator/Entity.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -85,7 +86,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $entity_type_id = $this->definition['entity_type'];
@@ -149,7 +150,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitOptionsForm(&$form, &$form_state, &$options = array()) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = array()) {
     // Filter out unused options so we don't store giant unnecessary arrays.
     $options['bundles'] = array_filter($options['bundles']);
   }
diff --git a/core/modules/views/src/Plugin/views/cache/Time.php b/core/modules/views/src/Plugin/views/cache/Time.php
index aa1194d..48fad3e 100644
--- a/core/modules/views/src/Plugin/views/cache/Time.php
+++ b/core/modules/views/src/Plugin/views/cache/Time.php
@@ -9,8 +9,8 @@
 
 use Drupal\Core\Datetime\Date as DateFormatter;
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Plugin\PluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Simple caching of query results for Views displays.
@@ -76,7 +76,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $options = array(60, 300, 1800, 3600, 21600, 518400);
     $options = array_map(array($this->dateFormatter, 'formatInterval'), array_combine($options, $options));
@@ -124,7 +124,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     $custom_fields = array('output_lifespan', 'results_lifespan');
     foreach ($custom_fields as $field) {
       if ($form_state['values']['cache_options'][$field] == 'custom' && !is_numeric($form_state['values']['cache_options'][$field . '_custom'])) {
diff --git a/core/modules/views/src/Plugin/views/display/Attachment.php b/core/modules/views/src/Plugin/views/display/Attachment.php
index 9673e55..1382933 100644
--- a/core/modules/views/src/Plugin/views/display/Attachment.php
+++ b/core/modules/views/src/Plugin/views/display/Attachment.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\display;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 
 /**
@@ -140,7 +141,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // It is very important to call the parent function here:
     parent::buildOptionsForm($form, $form_state);
 
@@ -214,7 +215,7 @@ public function buildOptionsForm(&$form, &$form_state) {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     // It is very important to call the parent function here:
     parent::submitOptionsForm($form, $form_state);
     switch ($form_state['section']) {
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index a5e6e15..b224567 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Theme\Registry;
@@ -1375,7 +1376,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     if ($this->defaultableSections($form_state['section'])) {
       views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
@@ -1867,7 +1868,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Validate the options form.
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     switch ($form_state['section']) {
       case 'display_title':
         if (empty($form_state['values']['display_title'])) {
@@ -1919,7 +1920,7 @@ public function validateOptionsForm(&$form, &$form_state) {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     // Not sure I like this being here, but it seems (?) like a logical place.
     $cache_plugin = $this->getPlugin('cache');
     if ($cache_plugin) {
@@ -2021,7 +2022,7 @@ public function submitOptionsForm(&$form, &$form_state) {
   /**
    * If override/revert was clicked, perform the proper toggle.
    */
-  public function optionsOverride($form, &$form_state) {
+  public function optionsOverride($form, FormStateInterface $form_state) {
     $this->setOverride($form_state['section']);
   }
 
@@ -2119,17 +2120,14 @@ public function renderMoreLink() {
   }
 
   /**
-   * Creates menu links, if this display provides some.
-   *
-   * @param array $existing_links
-   *   An array of already existing menu items provided by drupal.
+   * Gets menu links, if this display provides some.
    *
    * @return array
    *   The menu links registers for this display.
    *
-   * @see hook_menu_link_defaults()
+   * @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
    */
-  public function executeHookMenuLinkDefaults(array &$existing_links) {
+  public function getMenuLinks() {
     return array();
   }
 
diff --git a/core/modules/views/src/Plugin/views/display/Feed.php b/core/modules/views/src/Plugin/views/display/Feed.php
index ed7a571..a6e6fdd 100644
--- a/core/modules/views/src/Plugin/views/display/Feed.php
+++ b/core/modules/views/src/Plugin/views/display/Feed.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\display;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
 use Symfony\Component\HttpFoundation\Response;
@@ -193,7 +194,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\PathPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // It is very important to call the parent function here.
     parent::buildOptionsForm($form, $form_state);
 
@@ -239,7 +240,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::submitOptionsForm().
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
     switch ($form_state['section']) {
       case 'title':
diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php
index 21a4de2..ca099a2 100644
--- a/core/modules/views/src/Plugin/views/display/Page.php
+++ b/core/modules/views/src/Plugin/views/display/Page.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\display;
 
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
@@ -148,7 +149,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\callbackPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     switch ($form_state['section']) {
@@ -377,7 +378,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\callbackPluginBase::validateOptionsForm().
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     parent::validateOptionsForm($form, $form_state);
 
     if ($form_state['section'] == 'menu') {
@@ -403,7 +404,7 @@ public function validateOptionsForm(&$form, &$form_state) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\callbackPluginBase::submitOptionsForm().
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
 
     switch ($form_state['section']) {
diff --git a/core/modules/views/src/Plugin/views/display/PathPluginBase.php b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
index 4575678..58c9cfa 100644
--- a/core/modules/views/src/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\Form\FormErrorInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\Routing\RouteCompiler;
 use Drupal\Core\Routing\RouteProviderInterface;
@@ -280,7 +281,7 @@ public function alterRoutes(RouteCollection $collection) {
   /**
    * {@inheritdoc}
    */
-  public function executeHookMenuLinkDefaults(array &$existing_links) {
+  public function getMenuLinks() {
     $links = array();
 
     // Replace % with the link to our standard views argument loader
@@ -300,7 +301,10 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
     $view_route_names = $this->state->get('views.view_route_names') ?: array();
 
     $path = implode('/', $bits);
-    $menu_link_id = 'views.' . str_replace('/', '.', $path);
+    $view_id = $this->view->storage->id();
+    $display_id = $this->display['id'];
+    $view_id_display =  "{$view_id}.{$display_id}";
+    $menu_link_id = 'views.' . str_replace('/', '.', $view_id_display);
 
     if ($path) {
       $menu = $this->getOption('menu');
@@ -308,12 +312,11 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
         $links[$menu_link_id] = array();
         // Some views might override existing paths, so we have to set the route
         // name based upon the altering.
-        $view_id_display =  "{$this->view->storage->id()}.{$this->display['id']}";
         $links[$menu_link_id] = array(
           'route_name' => isset($view_route_names[$view_id_display]) ? $view_route_names[$view_id_display] : "view.$view_id_display",
           // Identify URL embedded arguments and correlate them to a handler.
           'load arguments'  => array($this->view->storage->id(), $this->display['id'], '%index'),
-          'machine_name' => $menu_link_id,
+          'id' => $menu_link_id,
         );
         $links[$menu_link_id]['title'] = $menu['title'];
         $links[$menu_link_id]['description'] = $menu['description'];
@@ -324,6 +327,11 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
 
         // Insert item into the proper menu.
         $links[$menu_link_id]['menu_name'] = $menu['name'];
+        // Keep track of where we came from.
+        $links[$menu_link_id]['metadata'] = array(
+          'view_id' => $view_id,
+          'display_id' => $display_id,
+        );
       }
     }
 
@@ -380,7 +388,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     switch ($form_state['section']) {
@@ -404,7 +412,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::validateOptionsForm().
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     parent::validateOptionsForm($form, $form_state);
 
     if ($form_state['section'] == 'path') {
@@ -421,7 +429,7 @@ public function validateOptionsForm(&$form, &$form_state) {
   /**
    * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::submitOptionsForm().
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
 
     if ($form_state['section'] == 'path') {
diff --git a/core/modules/views/src/Plugin/views/display_extender/DisplayExtenderPluginBase.php b/core/modules/views/src/Plugin/views/display_extender/DisplayExtenderPluginBase.php
index bbfdcd1..aebc614 100644
--- a/core/modules/views/src/Plugin/views/display_extender/DisplayExtenderPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display_extender/DisplayExtenderPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\display_extender;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\PluginBase;
 
@@ -46,17 +47,17 @@ public function defineOptionsAlter(&$options) { }
   /**
    * Provide a form to edit options for this plugin.
    */
-  public function buildOptionsForm(&$form, &$form_state) { }
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Validate the options form.
    */
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Handle any special handling on the validate form.
    */
-  public function submitOptionsForm(&$form, &$form_state) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Set up any variables on the view prior to execution.
diff --git a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
index edaa445..276a4dd 100644
--- a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
+++ b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php
@@ -8,6 +8,8 @@
 namespace Drupal\views\Plugin\views\exposed_form;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Form\ViewsExposedForm;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -51,7 +53,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['submit_button'] = array(
       '#type' => 'textfield',
@@ -127,14 +129,14 @@ public function buildOptionsForm(&$form, &$form_state) {
    */
   public function renderExposedForm($block = FALSE) {
     // Deal with any exposed filters we may have, before building.
-    $form_state = array(
+    $form_state = new FormState(array(
       'view' => &$this->view,
       'display' => &$this->view->display_handler->display,
       'method' => 'get',
       'rerender' => TRUE,
       'no_redirect' => TRUE,
       'always_process' => TRUE,
-    );
+    ));
 
     // Some types of displays (eg. attachments) may wish to use the exposed
     // filters of their parent displays instead of showing an additional
@@ -199,7 +201,7 @@ public function postExecute() { }
    * @param $form_state
    *   The form state. Passed by reference.
    */
-  public function exposedFormAlter(&$form, &$form_state) {
+  public function exposedFormAlter(&$form, FormStateInterface $form_state) {
     if (!empty($this->options['submit_button'])) {
       $form['actions']['submit']['#value'] = $this->options['submit_button'];
     }
@@ -274,7 +276,7 @@ public function exposedFormAlter(&$form, &$form_state) {
     }
   }
 
-  public function exposedFormValidate(&$form, &$form_state) {
+  public function exposedFormValidate(&$form, FormStateInterface $form_state) {
     if (isset($form_state['pager_plugin'])) {
       $form_state['pager_plugin']->exposedFormValidate($form, $form_state);
     }
@@ -286,12 +288,12 @@ public function exposedFormValidate(&$form, &$form_state) {
    * @param $form
    *   Nested array of form elements that comprise the form.
    * @param $form_state
-   *   A keyed array containing the current state of the form.
+   *   The current state of the form.
    * @param $exclude
    *   Nested array of keys to exclude of insert into
    *   $view->exposed_raw_input
    */
-  public function exposedFormSubmit(&$form, &$form_state, &$exclude) {
+  public function exposedFormSubmit(&$form, FormStateInterface $form_state, &$exclude) {
     if (!empty($form_state['values']['op']) && $form_state['values']['op'] == $this->options['reset_button_label']) {
       $this->resetForm($form, $form_state);
     }
@@ -301,7 +303,7 @@ public function exposedFormSubmit(&$form, &$form_state, &$exclude) {
     }
   }
 
-  public function resetForm(&$form, &$form_state) {
+  public function resetForm(&$form, FormStateInterface $form_state) {
     // _SESSION is not defined for users who are not logged in.
 
     // If filters are not overridden, store the 'remember' settings on the
diff --git a/core/modules/views/src/Plugin/views/exposed_form/InputRequired.php b/core/modules/views/src/Plugin/views/exposed_form/InputRequired.php
index 99f5ea4..af18617 100644
--- a/core/modules/views/src/Plugin/views/exposed_form/InputRequired.php
+++ b/core/modules/views/src/Plugin/views/exposed_form/InputRequired.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\exposed_form;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 
 /**
@@ -30,7 +31,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['text_input_required'] = array(
@@ -43,7 +44,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     $form_state['values']['exposed_form_options']['text_input_required_format'] = $form_state['values']['exposed_form_options']['text_input_required']['format'];
     $form_state['values']['exposed_form_options']['text_input_required'] = $form_state['values']['exposed_form_options']['text_input_required']['value'];
     parent::submitOptionsForm($form, $form_state);
diff --git a/core/modules/views/src/Plugin/views/field/Boolean.php b/core/modules/views/src/Plugin/views/field/Boolean.php
index cf4ef77..13b5858 100644
--- a/core/modules/views/src/Plugin/views/field/Boolean.php
+++ b/core/modules/views/src/Plugin/views/field/Boolean.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Component\Utility\Xss as UtilityXss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -61,7 +62,7 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
     $this->formats = array_merge($default_formats, $output_formats, $custom_format);
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     foreach ($this->formats as $key => $item) {
       $options[$key] = implode('/', $item);
     }
diff --git a/core/modules/views/src/Plugin/views/field/Counter.php b/core/modules/views/src/Plugin/views/field/Counter.php
index a8a4ffd..62b2580 100644
--- a/core/modules/views/src/Plugin/views/field/Counter.php
+++ b/core/modules/views/src/Plugin/views/field/Counter.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -32,7 +33,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['counter_start'] = array(
       '#type' => 'textfield',
       '#title' => t('Starting value'),
diff --git a/core/modules/views/src/Plugin/views/field/Custom.php b/core/modules/views/src/Plugin/views/field/Custom.php
index e3c347a..14e7e24 100644
--- a/core/modules/views/src/Plugin/views/field/Custom.php
+++ b/core/modules/views/src/Plugin/views/field/Custom.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -38,7 +39,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Remove the checkbox
diff --git a/core/modules/views/src/Plugin/views/field/Date.php b/core/modules/views/src/Plugin/views/field/Date.php
index 9125f3e..5888670 100644
--- a/core/modules/views/src/Plugin/views/field/Date.php
+++ b/core/modules/views/src/Plugin/views/field/Date.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Datetime\Date as DateFormatter;
@@ -79,7 +80,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
 
     $date_formats = array();
     foreach ($this->dateFormatStorage->loadMultiple() as $machine_name => $value) {
diff --git a/core/modules/views/src/Plugin/views/field/EntityLabel.php b/core/modules/views/src/Plugin/views/field/EntityLabel.php
index 60ad43e..376c497 100644
--- a/core/modules/views/src/Plugin/views/field/EntityLabel.php
+++ b/core/modules/views/src/Plugin/views/field/EntityLabel.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
@@ -85,7 +86,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['link_to_entity'] = array(
       '#title' => t('Link to entity'),
       '#description' => t('Make entity label a link to entity page.'),
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index 615f852..5acf50a 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -12,6 +12,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -479,7 +480,7 @@ protected function defineOptions() {
   /**
    * Performs some cleanup tasks on the options array before saving it.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     $options = &$form_state['values']['options'];
     $types = array('element_type', 'element_label_type', 'element_wrapper_type');
     $classes = array_combine(array('element_class', 'element_label_class', 'element_wrapper_class'), $types);
@@ -506,7 +507,7 @@ public function submitOptionsForm(&$form, &$form_state) {
    * Default options form that provides the label widget that all fields
    * should have.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $label = $this->label();
diff --git a/core/modules/views/src/Plugin/views/field/FileSize.php b/core/modules/views/src/Plugin/views/field/FileSize.php
index e89a1a4..57bd1bb 100644
--- a/core/modules/views/src/Plugin/views/field/FileSize.php
+++ b/core/modules/views/src/Plugin/views/field/FileSize.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -26,7 +27,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['file_size_display'] = array(
       '#title' => t('File size display'),
diff --git a/core/modules/views/src/Plugin/views/field/LanguageField.php b/core/modules/views/src/Plugin/views/field/LanguageField.php
index 7c6c35c..3878e6c 100644
--- a/core/modules/views/src/Plugin/views/field/LanguageField.php
+++ b/core/modules/views/src/Plugin/views/field/LanguageField.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -25,7 +26,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['native_language'] = array(
       '#title' => t('Native language'),
diff --git a/core/modules/views/src/Plugin/views/field/Links.php b/core/modules/views/src/Plugin/views/field/Links.php
index f466bc6..1d6a82a 100644
--- a/core/modules/views/src/Plugin/views/field/Links.php
+++ b/core/modules/views/src/Plugin/views/field/Links.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * A abstract handler which provides a collection of links.
  *
@@ -36,7 +38,7 @@ public function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::defineOptions().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     // Only show fields that precede this one.
     $field_options = $this->getPreviousFieldLabels();
diff --git a/core/modules/views/src/Plugin/views/field/MachineName.php b/core/modules/views/src/Plugin/views/field/MachineName.php
index e07da1f..4b3521b 100644
--- a/core/modules/views/src/Plugin/views/field/MachineName.php
+++ b/core/modules/views/src/Plugin/views/field/MachineName.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -52,7 +53,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['machine_name'] = array(
diff --git a/core/modules/views/src/Plugin/views/field/Numeric.php b/core/modules/views/src/Plugin/views/field/Numeric.php
index 7a4c994..df9343b 100644
--- a/core/modules/views/src/Plugin/views/field/Numeric.php
+++ b/core/modules/views/src/Plugin/views/field/Numeric.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -38,7 +39,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     if (!empty($this->definition['float'])) {
       $form['set_precision'] = array(
         '#type' => 'checkbox',
diff --git a/core/modules/views/src/Plugin/views/field/PrerenderList.php b/core/modules/views/src/Plugin/views/field/PrerenderList.php
index 4530423..c309879 100644
--- a/core/modules/views/src/Plugin/views/field/PrerenderList.php
+++ b/core/modules/views/src/Plugin/views/field/PrerenderList.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Field handler to provide a list of items.
  *
@@ -40,7 +42,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['type'] = array(
       '#type' => 'radios',
       '#title' => t('Display type'),
diff --git a/core/modules/views/src/Plugin/views/field/Serialized.php b/core/modules/views/src/Plugin/views/field/Serialized.php
index aa933eb..5d8c27b 100644
--- a/core/modules/views/src/Plugin/views/field/Serialized.php
+++ b/core/modules/views/src/Plugin/views/field/Serialized.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -27,7 +28,7 @@ protected function defineOptions() {
   }
 
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['format'] = array(
@@ -53,7 +54,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     // Require a key if the format is key.
     if ($form_state['values']['options']['format'] == 'key' && $form_state['values']['options']['key'] == '') {
       form_error($form['key'], $form_state, t('You have to enter a key if you want to display a key of the data.'));
diff --git a/core/modules/views/src/Plugin/views/field/TimeInterval.php b/core/modules/views/src/Plugin/views/field/TimeInterval.php
index 545f721..bd3fae4 100644
--- a/core/modules/views/src/Plugin/views/field/TimeInterval.php
+++ b/core/modules/views/src/Plugin/views/field/TimeInterval.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\field;
 
 use Drupal\Core\Datetime\Date as DateFormatter;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -64,7 +65,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['granularity'] = array(
diff --git a/core/modules/views/src/Plugin/views/field/Url.php b/core/modules/views/src/Plugin/views/field/Url.php
index 6b59c92..22ced7d 100644
--- a/core/modules/views/src/Plugin/views/field/Url.php
+++ b/core/modules/views/src/Plugin/views/field/Url.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ResultRow;
 
 /**
@@ -29,7 +30,7 @@ protected function defineOptions() {
   /**
    * Provide link to the page being visited.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['display_as_link'] = array(
       '#title' => t('Display as link'),
       '#type' => 'checkbox',
diff --git a/core/modules/views/src/Plugin/views/filter/BooleanOperator.php b/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
index 1158575..e0d2ed4 100644
--- a/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
+++ b/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
 
@@ -131,7 +132,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     if (empty($this->value_options)) {
       // Initialize the array of possible values for this filter.
       $this->getValueOptions();
@@ -162,7 +163,7 @@ protected function valueForm(&$form, &$form_state) {
     }
   }
 
-  protected function valueValidate($form, &$form_state) {
+  protected function valueValidate($form, FormStateInterface $form_state) {
     if (isset($form_state['values']['options']['value']) && $form_state['values']['options']['value'] == 'All' && !empty($form_state['values']['options']['expose']['required'])) {
       form_set_error('value', $form_state, t('You must select a value unless this is an non-required exposed filter.'));
     }
diff --git a/core/modules/views/src/Plugin/views/filter/Combine.php b/core/modules/views/src/Plugin/views/filter/Combine.php
index 3621378..12e6f22 100644
--- a/core/modules/views/src/Plugin/views/filter/Combine.php
+++ b/core/modules/views/src/Plugin/views/filter/Combine.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Filter handler which allows to search on multiple fields.
  *
@@ -28,7 +30,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $this->view->initStyle();
 
diff --git a/core/modules/views/src/Plugin/views/filter/Date.php b/core/modules/views/src/Plugin/views/filter/Date.php
index 52ea7ce..ead1f1d 100644
--- a/core/modules/views/src/Plugin/views/filter/Date.php
+++ b/core/modules/views/src/Plugin/views/filter/Date.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Filter to handle dates stored as a timestamp.
  *
@@ -28,7 +30,7 @@ protected function defineOptions() {
   /**
    * Add a type selector to the value form
    */
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     if (empty($form_state['exposed'])) {
       $form['value']['type'] = array(
         '#type' => 'radios',
@@ -43,7 +45,7 @@ protected function valueForm(&$form, &$form_state) {
     parent::valueForm($form, $form_state);
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     parent::validateOptionsForm($form, $form_state);
 
     if (!empty($this->options['exposed']) && empty($form_state['values']['options']['expose']['required'])) {
@@ -54,7 +56,7 @@ public function validateOptionsForm(&$form, &$form_state) {
     $this->validateValidTime($form['value'], $form_state, $form_state['values']['options']['operator'], $form_state['values']['options']['value']);
   }
 
-  public function validateExposed(&$form, &$form_state) {
+  public function validateExposed(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed'])) {
       return;
     }
@@ -79,7 +81,7 @@ public function validateExposed(&$form, &$form_state) {
   /**
    * Validate that the time values convert to something usable.
    */
-  public function validateValidTime(&$form, array &$form_state, $operator, $value) {
+  public function validateValidTime(&$form, FormStateInterface $form_state, $operator, $value) {
     $operators = $this->operators();
 
     if ($operators[$operator]['values'] == 1) {
@@ -103,7 +105,7 @@ public function validateValidTime(&$form, array &$form_state, $operator, $value)
   /**
    * Validate the build group options form.
    */
-  protected function buildGroupValidate($form, &$form_state) {
+  protected function buildGroupValidate($form, FormStateInterface $form_state) {
     // Special case to validate grouped date filters, this is because the
     // $group['value'] array contains the type of filter (date or offset)
     // and therefore the number of items the comparission has to be done
diff --git a/core/modules/views/src/Plugin/views/filter/Equality.php b/core/modules/views/src/Plugin/views/filter/Equality.php
index f0cda43..f83cefa 100644
--- a/core/modules/views/src/Plugin/views/filter/Equality.php
+++ b/core/modules/views/src/Plugin/views/filter/Equality.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Simple filter to handle equal to / not equal to filters
  *
@@ -32,7 +34,7 @@ public function operatorOptions() {
   /**
    * Provide a simple textfield for equality
    */
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     $form['value'] = array(
       '#type' => 'textfield',
       '#title' => t('Value'),
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index fe110db..c92184e 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\Component\Utility\String as UtilityString;
@@ -196,7 +197,7 @@ public function isAGroup() {
    * or to at least make sure all of the functions in this form
    * are called.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     if ($this->canExpose()) {
       $this->showExposeButton($form, $form_state);
@@ -237,7 +238,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Simple validate handler
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     $this->operatorValidate($form, $form_state);
     $this->valueValidate($form, $form_state);
     if (!empty($this->options['exposed']) && !$this->isAGroup()) {
@@ -251,7 +252,7 @@ public function validateOptionsForm(&$form, &$form_state) {
   /**
    * Simple submit handler
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     unset($form_state['values']['expose_button']); // don't store this.
     unset($form_state['values']['group_button']); // don't store this.
     if (!$this->isAGroup()) {
@@ -269,7 +270,7 @@ public function submitOptionsForm(&$form, &$form_state) {
   /**
    * Shortcut to display the operator form.
    */
-  public function showOperatorForm(&$form, &$form_state) {
+  public function showOperatorForm(&$form, FormStateInterface $form_state) {
     $this->operatorForm($form, $form_state);
     $form['operator']['#prefix'] = '<div class="views-group-box views-left-30">';
     $form['operator']['#suffix'] = '</div>';
@@ -283,7 +284,7 @@ public function showOperatorForm(&$form, &$form_state) {
    *
    * @see buildOptionsForm()
    */
-  protected function operatorForm(&$form, &$form_state) {
+  protected function operatorForm(&$form, FormStateInterface $form_state) {
     $options = $this->operatorOptions();
     if (!empty($options)) {
       $form['operator'] = array(
@@ -304,18 +305,18 @@ public function operatorOptions() { return array(); }
   /**
    * Validate the operator form.
    */
-  protected function operatorValidate($form, &$form_state) { }
+  protected function operatorValidate($form, FormStateInterface $form_state) { }
 
   /**
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function operatorSubmit($form, &$form_state) { }
+  public function operatorSubmit($form, FormStateInterface $form_state) { }
 
   /**
    * Shortcut to display the value form.
    */
-  protected function showValueForm(&$form, &$form_state) {
+  protected function showValueForm(&$form, FormStateInterface $form_state) {
     $this->valueForm($form, $form_state);
     if (empty($this->no_operator)) {
       $form['value']['#prefix'] = '<div class="views-group-box views-right-70">' . (isset($form['value']['#prefix']) ? $form['value']['#prefix'] : '');
@@ -331,23 +332,25 @@ protected function showValueForm(&$form, &$form_state) {
    *
    * @see buildOptionsForm()
    */
-  protected function valueForm(&$form, &$form_state) { $form['value'] = array(); }
+  protected function valueForm(&$form, FormStateInterface $form_state) {
+    $form['value'] = array();
+  }
 
   /**
    * Validate the options form.
    */
-  protected function valueValidate($form, &$form_state) { }
+  protected function valueValidate($form, FormStateInterface $form_state) { }
 
   /**
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  protected function valueSubmit($form, &$form_state) { }
+  protected function valueSubmit($form, FormStateInterface $form_state) { }
 
   /**
    * Shortcut to display the exposed options form.
    */
-  public function showBuildGroupForm(&$form, &$form_state) {
+  public function showBuildGroupForm(&$form, FormStateInterface $form_state) {
     if (empty($this->options['is_grouped'])) {
       return;
     }
@@ -370,7 +373,7 @@ public function showBuildGroupForm(&$form, &$form_state) {
   /**
    * Shortcut to display the build_group/hide button.
    */
-  protected function showBuildGroupButton(&$form, &$form_state) {
+  protected function showBuildGroupButton(&$form, FormStateInterface $form_state) {
 
     $form['group_button'] = array(
       '#prefix' => '<div class="views-grouped clearfix">',
@@ -422,7 +425,7 @@ protected function showBuildGroupButton(&$form, &$form_state) {
   /**
    * Displays the Build Group form.
    */
-  public function buildGroupForm($form, &$form_state) {
+  public function buildGroupForm($form, FormStateInterface $form_state) {
     $item = &$this->options;
     // flip. If the filter was a group, set back to a standard filter.
     $item['is_grouped'] = empty($item['is_grouped']);
@@ -445,7 +448,7 @@ public function buildGroupForm($form, &$form_state) {
   /**
    * Shortcut to display the expose/hide button.
    */
-  public function showExposeButton(&$form, &$form_state) {
+  public function showExposeButton(&$form, FormStateInterface $form_state) {
     $form['expose_button'] = array(
       '#prefix' => '<div class="views-expose clearfix">',
       '#suffix' => '</div>',
@@ -498,7 +501,7 @@ public function showExposeButton(&$form, &$form_state) {
    *
    * @see buildOptionsForm()
    */
-  public function buildExposeForm(&$form, &$form_state) {
+  public function buildExposeForm(&$form, FormStateInterface $form_state) {
     $form['#theme'] = 'views_ui_expose_filter_form';
     // #flatten will move everything from $form['expose'][$key] to $form[$key]
     // prior to rendering. That's why the preRender for it needs to run first,
@@ -608,7 +611,7 @@ public function buildExposeForm(&$form, &$form_state) {
   /**
    * Validate the options form.
    */
-  public function validateExposeForm($form, &$form_state) {
+  public function validateExposeForm($form, FormStateInterface $form_state) {
     if (empty($form_state['values']['options']['expose']['identifier'])) {
       form_error($form['expose']['identifier'], $form_state, t('The identifier is required if the filter is exposed.'));
     }
@@ -625,7 +628,7 @@ public function validateExposeForm($form, &$form_state) {
   /**
    * Validate the build group options form.
    */
-  protected function buildGroupValidate($form, &$form_state) {
+  protected function buildGroupValidate($form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['options']['group_info'])) {
       if (empty($form_state['values']['options']['group_info']['identifier'])) {
         form_error($form['group_info']['identifier'], $form_state, t('The identifier is required if the filter is exposed.'));
@@ -671,7 +674,7 @@ protected function buildGroupValidate($form, &$form_state) {
   /**
    * Save new group items, re-enumerates and remove groups marked to delete.
    */
-  protected function buildGroupSubmit($form, &$form_state) {
+  protected function buildGroupSubmit($form, FormStateInterface $form_state) {
     $groups = array();
     uasort($form_state['values']['options']['group_info']['group_items'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
     // Filter out removed items.
@@ -739,7 +742,7 @@ protected function buildGroupOptions() {
    * Build a form containing a group of operator | values to apply as a
    * single filter.
    */
-  public function groupForm(&$form, &$form_state) {
+  public function groupForm(&$form, FormStateInterface $form_state) {
     if (!empty($this->options['group_info']['optional']) && !$this->multipleExposedInput()) {
       $groups = array('All' => t('- Any -'));
     }
@@ -783,7 +786,7 @@ public function groupForm(&$form, &$form_state) {
    *
    * You can override this if it doesn't do what you expect.
    */
-  public function buildExposedForm(&$form, &$form_state) {
+  public function buildExposedForm(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed'])) {
       return;
     }
@@ -829,7 +832,7 @@ public function buildExposedForm(&$form, &$form_state) {
    * Build the form to let users create the group of exposed filters.
    * This form is displayed when users click on button 'Build group'
    */
-  protected function buildExposedFiltersGroupForm(&$form, &$form_state) {
+  protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed']) || empty($this->options['is_grouped'])) {
       return;
     }
@@ -1092,7 +1095,7 @@ protected function buildExposedFiltersGroupForm(&$form, &$form_state) {
   /**
    * Add a new group to the exposed filter groups.
    */
-  public function addGroupForm($form, &$form_state) {
+  public function addGroupForm($form, FormStateInterface $form_state) {
     $item = &$this->options;
 
     // Add a new row.
diff --git a/core/modules/views/src/Plugin/views/filter/InOperator.php b/core/modules/views/src/Plugin/views/filter/InOperator.php
index 1902b3b..f99041e 100644
--- a/core/modules/views/src/Plugin/views/filter/InOperator.php
+++ b/core/modules/views/src/Plugin/views/filter/InOperator.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String as UtilityString;
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
 
@@ -79,7 +80,7 @@ public function defaultExposeOptions() {
     $this->options['expose']['reduce'] = FALSE;
   }
 
-  public function buildExposeForm(&$form, &$form_state) {
+  public function buildExposeForm(&$form, FormStateInterface $form_state) {
     parent::buildExposeForm($form, $form_state);
     $form['expose']['reduce'] = array(
       '#type' => 'checkbox',
@@ -165,7 +166,7 @@ protected function operatorValues($values = 1) {
     return $options;
   }
 
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     $form['value'] = array();
     $options = array();
 
@@ -295,7 +296,7 @@ public function acceptExposedInput($input) {
     return parent::acceptExposedInput($input);
   }
 
-  protected function valueSubmit($form, &$form_state) {
+  protected function valueSubmit($form, FormStateInterface $form_state) {
     // Drupal's FAPI system automatically puts '0' in for any checkbox that
     // was not set, and the key to the checkbox if it is set.
     // Unfortunately, this means that if the key to that checkbox is 0,
diff --git a/core/modules/views/src/Plugin/views/filter/ManyToOne.php b/core/modules/views/src/Plugin/views/filter/ManyToOne.php
index a399964..cc8b448 100644
--- a/core/modules/views/src/Plugin/views/filter/ManyToOne.php
+++ b/core/modules/views/src/Plugin/views/filter/ManyToOne.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ManyToOneHelper;
@@ -107,7 +108,7 @@ function operators() {
   }
 
   protected $valueFormType = 'select';
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     parent::valueForm($form, $form_state);
 
     if (empty($form_state['exposed'])) {
diff --git a/core/modules/views/src/Plugin/views/filter/Numeric.php b/core/modules/views/src/Plugin/views/filter/Numeric.php
index 53b94fa..0348a33 100644
--- a/core/modules/views/src/Plugin/views/filter/Numeric.php
+++ b/core/modules/views/src/Plugin/views/filter/Numeric.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String as UtilityString;
 use Drupal\Core\Database\Database;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Simple filter to handle greater than/less than filters
@@ -139,7 +140,7 @@ protected function operatorValues($values = 1) {
   /**
    * Provide a simple textfield for equality
    */
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     $form['value']['#tree'] = TRUE;
 
     // We have to make some choices when creating this as an exposed
diff --git a/core/modules/views/src/Plugin/views/filter/String.php b/core/modules/views/src/Plugin/views/filter/String.php
index ea1b3fe..185252d 100644
--- a/core/modules/views/src/Plugin/views/filter/String.php
+++ b/core/modules/views/src/Plugin/views/filter/String.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String as UtilityString;
 use Drupal\Core\Database\Database;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Basic textfield filter to handle string filtering commands
@@ -183,7 +184,7 @@ protected function operatorValues($values = 1) {
   /**
    * Provide a simple textfield for equality
    */
-  protected function valueForm(&$form, &$form_state) {
+  protected function valueForm(&$form, FormStateInterface $form_state) {
     // We have to make some choices when creating this as an exposed
     // filter form. For example, if the operator is locked and thus
     // not rendered, we can't render dependencies; instead we only
diff --git a/core/modules/views/src/Plugin/views/pager/Full.php b/core/modules/views/src/Plugin/views/pager/Full.php
index fda4c4e..ed8bbd1 100644
--- a/core/modules/views/src/Plugin/views/pager/Full.php
+++ b/core/modules/views/src/Plugin/views/pager/Full.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\pager;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * The plugin to handle full pager.
  *
@@ -41,7 +43,7 @@ protected function defineOptions() {
   /**
    * Overrides \Drupal\views\Plugin\views\SqlBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['quantity'] = array(
diff --git a/core/modules/views/src/Plugin/views/pager/None.php b/core/modules/views/src/Plugin/views/pager/None.php
index e5ccad3..15bfa13 100644
--- a/core/modules/views/src/Plugin/views/pager/None.php
+++ b/core/modules/views/src/Plugin/views/pager/None.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\pager;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 
@@ -51,7 +52,7 @@ protected function defineOptions() {
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['offset'] = array(
       '#type' => 'textfield',
diff --git a/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php b/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php
index b5a7af2..12a7098 100644
--- a/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php
+++ b/core/modules/views/src/Plugin/views/pager/PagerPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\pager;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\ViewExecutable;
 
@@ -119,12 +120,12 @@ public function getPagerId() {
   /**
    * Provide the default form form for validating options
    */
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Provide the default form form for submitting options
    */
-  public function submitOptionsForm(&$form, &$form_state) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Return a string to display as the clickable title for the
@@ -216,11 +217,11 @@ public function hasMoreRecords() {
       && $this->total_items > (intval($this->current_page) + 1) * $this->getItemsPerPage();
   }
 
-  public function exposedFormAlter(&$form, &$form_state) { }
+  public function exposedFormAlter(&$form, FormStateInterface $form_state) { }
 
-  public function exposedFormValidate(&$form, &$form_state) { }
+  public function exposedFormValidate(&$form, FormStateInterface $form_state) { }
 
-  public function exposedFormSubmit(&$form, &$form_state, &$exclude) { }
+  public function exposedFormSubmit(&$form, FormStateInterface $form_state, &$exclude) { }
 
   public function usesExposed() {
     return FALSE;
diff --git a/core/modules/views/src/Plugin/views/pager/Some.php b/core/modules/views/src/Plugin/views/pager/Some.php
index ded554f..d024960 100644
--- a/core/modules/views/src/Plugin/views/pager/Some.php
+++ b/core/modules/views/src/Plugin/views/pager/Some.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\pager;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Plugin for views without pagers.
  *
@@ -39,7 +41,7 @@ protected function defineOptions() {
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $pager_text = $this->displayHandler->getPagerText();
     $form['items_per_page'] = array(
diff --git a/core/modules/views/src/Plugin/views/pager/SqlBase.php b/core/modules/views/src/Plugin/views/pager/SqlBase.php
index 7aeb69e..c38edd9 100644
--- a/core/modules/views/src/Plugin/views/pager/SqlBase.php
+++ b/core/modules/views/src/Plugin/views/pager/SqlBase.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\pager;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * A common base class for sql based pager.
  */
@@ -42,7 +44,7 @@ protected function defineOptions() {
   /**
    * Provide the default form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $pager_text = $this->displayHandler->getPagerText();
     $form['items_per_page'] = array(
@@ -176,7 +178,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     );
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     // Only accept integer values.
     $error = FALSE;
     $exposed_options = $form_state['values']['pager_options']['expose']['items_per_page_options'];
@@ -335,7 +337,7 @@ protected function isOffsetExposed() {
     return !empty($this->options['expose']['offset']);
   }
 
-  public function exposedFormAlter(&$form, &$form_state) {
+  public function exposedFormAlter(&$form, FormStateInterface $form_state) {
     if ($this->itemsPerPageExposed()) {
       $options = explode(',', $this->options['expose']['items_per_page_options']);
       $sanitized_options = array();
@@ -366,7 +368,7 @@ public function exposedFormAlter(&$form, &$form_state) {
     }
   }
 
-  public function exposedFormValidate(&$form, &$form_state) {
+  public function exposedFormValidate(&$form, FormStateInterface $form_state) {
     if (!empty($form_state['values']['offset']) && trim($form_state['values']['offset'])) {
       if (!is_numeric($form_state['values']['offset']) || $form_state['values']['offset'] < 0) {
         form_set_error('offset', $form_state, t('Offset must be an number greather or equal than 0.'));
diff --git a/core/modules/views/src/Plugin/views/query/QueryPluginBase.php b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
index 4e917c1..4097efa 100644
--- a/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
+++ b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\query;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
@@ -108,9 +109,9 @@ public function addSignature(ViewExecutable $view) { }
    */
   public function getAggregationInfo() { }
 
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
-  public function submitOptionsForm(&$form, &$form_state) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
 
   public function summaryTitle() {
     return t('Settings');
diff --git a/core/modules/views/src/Plugin/views/query/Sql.php b/core/modules/views/src/Plugin/views/query/Sql.php
index 6e2f188..1cabb79 100644
--- a/core/modules/views/src/Plugin/views/query/Sql.php
+++ b/core/modules/views/src/Plugin/views/query/Sql.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Database\Database;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\Core\Database\DatabaseExceptionWrapper;
 use Drupal\views\Plugin\views\join\JoinPluginBase;
@@ -200,7 +201,7 @@ protected function defineOptions() {
   /**
    * Add settings for the ui.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['disable_sql_rewrite'] = array(
@@ -240,7 +241,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Special submit handling.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     $element = array('#parents' => array('query', 'options', 'query_tags'));
     $value = explode(',', NestedArray::getValue($form_state['values'], $element['#parents']));
     $value = array_filter(array_map('trim', $value));
diff --git a/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
index 7a85bbc..621b1c1 100644
--- a/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
+++ b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\relationship;
 
 use Drupal\Core\Database\Query\AlterableInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 
 /**
@@ -81,7 +82,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Get the sorts that apply to our base.
@@ -168,7 +169,7 @@ protected function getTemporaryView() {
   /**
    * When the form is submitted, make sure to clear the subquery string cache.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     $cid = 'views_relationship_groupwise_max:' . $this->view->storage->id() . ':' . $this->view->current_display . ':' . $this->options['id'];
     \Drupal::cache('views_results')->delete($cid);
   }
diff --git a/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php b/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
index a52d7dd..a75ffeb 100644
--- a/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
+++ b/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\relationship;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\HandlerBase;
@@ -104,7 +105,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     unset($form['admin_label']['#fieldset']);
diff --git a/core/modules/views/src/Plugin/views/row/EntityRow.php b/core/modules/views/src/Plugin/views/row/EntityRow.php
index c46d354..d830017 100644
--- a/core/modules/views/src/Plugin/views/row/EntityRow.php
+++ b/core/modules/views/src/Plugin/views/row/EntityRow.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\DependencyInjection\Container;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
@@ -125,7 +126,7 @@ protected function defineOptions() {
   /**
    * Overrides Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['view_mode'] = array(
diff --git a/core/modules/views/src/Plugin/views/row/Fields.php b/core/modules/views/src/Plugin/views/row/Fields.php
index d49b213..5851d49 100644
--- a/core/modules/views/src/Plugin/views/row/Fields.php
+++ b/core/modules/views/src/Plugin/views/row/Fields.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * The basic 'fields' row plugin
  *
@@ -45,7 +47,7 @@ protected function defineOptions() {
   /**
    * Provide a form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $options = $this->displayHandler->getFieldLabels();
 
@@ -99,7 +101,7 @@ public function buildOptionsForm(&$form, &$form_state) {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     $form_state['values']['row_options']['inline'] = array_filter($form_state['values']['row_options']['inline']);
   }
 
diff --git a/core/modules/views/src/Plugin/views/row/OpmlFields.php b/core/modules/views/src/Plugin/views/row/OpmlFields.php
index 2274f66..2e936f5 100644
--- a/core/modules/views/src/Plugin/views/row/OpmlFields.php
+++ b/core/modules/views/src/Plugin/views/row/OpmlFields.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Renders an OPML item based on fields.
  *
@@ -46,7 +48,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $initial_labels = array('' => $this->t('- None -'));
diff --git a/core/modules/views/src/Plugin/views/row/RowPluginBase.php b/core/modules/views/src/Plugin/views/row/RowPluginBase.php
index 41deced..905f04e 100644
--- a/core/modules/views/src/Plugin/views/row/RowPluginBase.php
+++ b/core/modules/views/src/Plugin/views/row/RowPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
@@ -78,7 +79,7 @@ protected function defineOptions() {
   /**
    * Provide a form for setting options.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     if (isset($this->base_table)) {
       $executable = $form_state['view']->getExecutable();
@@ -127,13 +128,13 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Validate the options form.
    */
-  public function validateOptionsForm(&$form, &$form_state) { }
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  public function submitOptionsForm(&$form, &$form_state) { }
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/views/src/Plugin/views/row/RssFields.php b/core/modules/views/src/Plugin/views/row/RssFields.php
index b59b72e..48dcefe 100644
--- a/core/modules/views/src/Plugin/views/row/RssFields.php
+++ b/core/modules/views/src/Plugin/views/row/RssFields.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Renders an RSS item based on fields.
  *
@@ -39,7 +41,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $initial_labels = array('' => t('- None -'));
diff --git a/core/modules/views/src/Plugin/views/sort/Date.php b/core/modules/views/src/Plugin/views/sort/Date.php
index 558321d..6c0b754 100644
--- a/core/modules/views/src/Plugin/views/sort/Date.php
+++ b/core/modules/views/src/Plugin/views/sort/Date.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\sort;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Basic sort handler for dates.
  *
@@ -25,7 +27,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['granularity'] = array(
diff --git a/core/modules/views/src/Plugin/views/sort/MenuHierarchy.php b/core/modules/views/src/Plugin/views/sort/MenuHierarchy.php
deleted file mode 100644
index 2d8a5fc..0000000
--- a/core/modules/views/src/Plugin/views/sort/MenuHierarchy.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\views\Plugin\views\sort\MenuHierarchy.
- */
-
-namespace Drupal\views\Plugin\views\sort;
-
-use Drupal\views\Views;
-
-/**
- * Sort in menu hierarchy order.
- *
- * Given a field name of 'p' this produces an ORDER BY on p1, p2, ..., p9;
- * and optionally injects multiple joins to {menu_links} to sort by weight
- * and title as well.
- *
- * This is only really useful for the {menu_links} table.
- *
- * @ViewsSort("menu_hierarchy")
- */
-class MenuHierarchy extends SortPluginBase {
-
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-    $options['sort_within_level'] = array('default' => FALSE);
-    return $options;
-  }
-
-  public function buildOptionsForm(&$form, &$form_state) {
-    parent::buildOptionsForm($form, $form_state);
-    $form['sort_within_level'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Sort within each hierarchy level'),
-      '#description' => t('Enable this to sort the items within each level of the hierarchy by weight and title.  Warning: this may produce a slow query.'),
-      '#default_value' => $this->options['sort_within_level'],
-    );
-  }
-
-  public function query() {
-    $this->ensureMyTable();
-    $max_depth = isset($this->definition['max depth']) ? $this->definition['max depth'] : MENU_MAX_DEPTH;
-    for ($i = 1; $i <= $max_depth; ++$i) {
-      if ($this->options['sort_within_level']) {
-        $definition = array(
-          'table' => 'menu_links',
-          'field' => 'mlid',
-          'left_table' => $this->tableAlias,
-          'left_field' => $this->field . $i
-        );
-        $join = Views::pluginManager('join')->createInstance('standard', $definition);
-
-        $menu_links = $this->query->addTable('menu_links', NULL, $join);
-        $this->query->addOrderBy($menu_links, 'weight', $this->options['order']);
-        $this->query->addOrderBy($menu_links, 'link_title', $this->options['order']);
-      }
-
-      // We need this even when also sorting by weight and title, to make sure
-      // that children of two parents with the same weight and title are
-      // correctly separated.
-      $this->query->addOrderBy($this->tableAlias, $this->field . $i, $this->options['order']);
-    }
-  }
-
-}
diff --git a/core/modules/views/src/Plugin/views/sort/Random.php b/core/modules/views/src/Plugin/views/sort/Random.php
index ebce478..f0223df 100644
--- a/core/modules/views/src/Plugin/views/sort/Random.php
+++ b/core/modules/views/src/Plugin/views/sort/Random.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\sort;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Handle a random sort.
  *
@@ -25,7 +27,7 @@ public function query() {
     $this->query->addOrderBy('rand');
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['order']['#access'] = FALSE;
   }
diff --git a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
index 5623ebe..cfe4d3f 100644
--- a/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
+++ b/core/modules/views/src/Plugin/views/sort/SortPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\sort;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\HandlerBase;
 
 /**
@@ -77,7 +78,7 @@ public function adminSummary() {
   /**
    * Basic options for all sort criteria
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     if ($this->canExpose()) {
       $this->showExposeButton($form, $form_state);
@@ -93,7 +94,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Shortcut to display the expose/hide button.
    */
-  public function showExposeButton(&$form, &$form_state) {
+  public function showExposeButton(&$form, FormStateInterface $form_state) {
     $form['expose_button'] = array(
       '#prefix' => '<div class="views-expose clearfix">',
       '#suffix' => '</div>',
@@ -144,7 +145,7 @@ public function showExposeButton(&$form, &$form_state) {
   /**
    * Simple validate handler
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     $this->sortValidate($form, $form_state);
     if (!empty($this->options['exposed'])) {
       $this->validateExposeForm($form, $form_state);
@@ -155,7 +156,7 @@ public function validateOptionsForm(&$form, &$form_state) {
   /**
    * Simple submit handler
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     unset($form_state['values']['expose_button']); // don't store this.
     $this->sortSubmit($form, $form_state);
     if (!empty($this->options['exposed'])) {
@@ -166,7 +167,7 @@ public function submitOptionsForm(&$form, &$form_state) {
   /**
    * Shortcut to display the value form.
    */
-  protected function showSortForm(&$form, &$form_state) {
+  protected function showSortForm(&$form, FormStateInterface $form_state) {
     $options = $this->sortOptions();
     if (!empty($options)) {
       $form['order'] = array(
@@ -178,9 +179,9 @@ protected function showSortForm(&$form, &$form_state) {
     }
   }
 
-  protected function sortValidate(&$form, &$form_state) { }
+  protected function sortValidate(&$form, FormStateInterface $form_state) { }
 
-  public function sortSubmit(&$form, &$form_state) { }
+  public function sortSubmit(&$form, FormStateInterface $form_state) { }
 
   /**
    * Provide a list of options for the default sort form.
@@ -193,7 +194,7 @@ protected function sortOptions() {
     );
   }
 
-  public function buildExposeForm(&$form, &$form_state) {
+  public function buildExposeForm(&$form, FormStateInterface $form_state) {
     // #flatten will move everything from $form['expose'][$key] to $form[$key]
     // prior to rendering. That's why the preRender for it needs to run first,
     // so that when the next preRender (the one for fieldsets) runs, it gets
diff --git a/core/modules/views/src/Plugin/views/style/DefaultSummary.php b/core/modules/views/src/Plugin/views/style/DefaultSummary.php
index 693c02a..7401a95 100644
--- a/core/modules/views/src/Plugin/views/style/DefaultSummary.php
+++ b/core/modules/views/src/Plugin/views/style/DefaultSummary.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\style\StylePluginBase;
 
 /**
@@ -41,7 +42,7 @@ public function query() {
     }
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     $form['base_path'] = array(
       '#type' => 'textfield',
       '#title' => t('Base path'),
diff --git a/core/modules/views/src/Plugin/views/style/Grid.php b/core/modules/views/src/Plugin/views/style/Grid.php
index 11918f7..ab5c6a2 100644
--- a/core/modules/views/src/Plugin/views/style/Grid.php
+++ b/core/modules/views/src/Plugin/views/style/Grid.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Style plugin to render each item in a grid cell.
  *
@@ -47,7 +49,7 @@ protected function defineOptions() {
   /**
    * {@inheritdoc}
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['columns'] = array(
       '#type' => 'number',
diff --git a/core/modules/views/src/Plugin/views/style/HtmlList.php b/core/modules/views/src/Plugin/views/style/HtmlList.php
index 9d18903..bf4422d 100644
--- a/core/modules/views/src/Plugin/views/style/HtmlList.php
+++ b/core/modules/views/src/Plugin/views/style/HtmlList.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Style plugin to render each item in an ordered or unordered list.
  *
@@ -52,7 +54,7 @@ protected function defineOptions() {
   /**
    * Render the given style.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['type'] = array(
       '#type' => 'radios',
diff --git a/core/modules/views/src/Plugin/views/style/Mapping.php b/core/modules/views/src/Plugin/views/style/Mapping.php
index 101d32f..7c538a3 100644
--- a/core/modules/views/src/Plugin/views/style/Mapping.php
+++ b/core/modules/views/src/Plugin/views/style/Mapping.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Allows fields to be mapped to specific use cases.
  *
@@ -70,7 +72,7 @@ protected function defineOptions() {
   /**
    * Overrides Drupal\views\Plugin\views\style\StylePluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     // Get the mapping.
diff --git a/core/modules/views/src/Plugin/views/style/Rss.php b/core/modules/views/src/Plugin/views/style/Rss.php
index 362370f..996684d 100644
--- a/core/modules/views/src/Plugin/views/style/Rss.php
+++ b/core/modules/views/src/Plugin/views/style/Rss.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\style;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Default style plugin to render an RSS feed.
@@ -74,7 +75,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['description'] = array(
diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
index 6662bf8..2f18209 100644
--- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php
+++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\wizard\WizardInterface;
@@ -244,7 +245,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     // Only fields-based views can handle grouping.  Style plugins can also exclude
     // themselves from being groupable by setting their "usesGrouping" property
@@ -335,7 +336,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     }
   }
 
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     // Don't run validation on style plugins without the grouping setting.
     if (isset($form_state['values']['style_options']['grouping'])) {
       // Don't save grouping if no field is specified.
@@ -352,12 +353,12 @@ public function validateOptionsForm(&$form, &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param string $type
    *    The display type, either block or page.
    */
-  public function wizardForm(&$form, &$form_state, $type) {
+  public function wizardForm(&$form, FormStateInterface $form_state, $type) {
   }
 
   /**
@@ -365,8 +366,8 @@ public function wizardForm(&$form, &$form_state, $type) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param \Drupal\views\Plugin\views\wizard\WizardInterface $wizard
    *   The current used wizard.
    * @param array $display_options
@@ -375,7 +376,7 @@ public function wizardForm(&$form, &$form_state, $type) {
    * @param string $display_type
    *   The display type, either block or page.
    */
-  public function wizardSubmit(&$form, &$form_state, WizardInterface $wizard, &$display_options, $display_type) {
+  public function wizardSubmit(&$form, FormStateInterface $form_state, WizardInterface $wizard, &$display_options, $display_type) {
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/views/style/Table.php b/core/modules/views/src/Plugin/views/style/Table.php
index 789857e..69c8b18 100644
--- a/core/modules/views/src/Plugin/views/style/Table.php
+++ b/core/modules/views/src/Plugin/views/style/Table.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\style;
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\wizard\WizardInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -196,7 +197,7 @@ public function sanitizeColumns($columns, $fields = NULL) {
   /**
    * Render the given style.
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $handlers = $this->displayHandler->getHandlers('field');
     if (empty($handlers)) {
@@ -411,7 +412,7 @@ public function evenEmpty() {
     return parent::evenEmpty() || !empty($this->options['empty_table']);
   }
 
-  public function wizardSubmit(&$form, &$form_state, WizardInterface $wizard, &$display_options, $display_type) {
+  public function wizardSubmit(&$form, FormStateInterface $form_state, WizardInterface $wizard, &$display_options, $display_type) {
     // If any of the displays use the table style, make sure that the fields
     // always have a labels by unsetting the override.
     foreach ($display_options['default']['fields'] as &$field) {
diff --git a/core/modules/views/src/Plugin/views/style/UnformattedSummary.php b/core/modules/views/src/Plugin/views/style/UnformattedSummary.php
index 3c7d47b..05c9e8e 100644
--- a/core/modules/views/src/Plugin/views/style/UnformattedSummary.php
+++ b/core/modules/views/src/Plugin/views/style/UnformattedSummary.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * The default style plugin for summaries.
  *
@@ -29,7 +31,7 @@ protected function defineOptions() {
     return $options;
   }
 
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $form['inline'] = array(
       '#type' => 'checkbox',
diff --git a/core/modules/views/src/Plugin/views/wizard/WizardInterface.php b/core/modules/views/src/Plugin/views/wizard/WizardInterface.php
index 6e1a548..893afee 100644
--- a/core/modules/views/src/Plugin/views/wizard/WizardInterface.php
+++ b/core/modules/views/src/Plugin/views/wizard/WizardInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Plugin\views\wizard;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Defines a common interface for Views Wizard plugins.
  *
@@ -22,34 +24,34 @@
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
    *   Returns the changed wizard form.
    */
-  public function buildForm(array $form, array &$form_state);
+  public function buildForm(array $form, FormStateInterface $form_state);
 
   /**
    * Validate form and values.
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
    *   An empty array if the view is valid; an array of error strings if it is
    *   not.
    */
-  public function validateView(array $form, array &$form_state);
+  public function validateView(array $form, FormStateInterface $form_state);
 
   /**
    * Creates a view from values that have already been validated.
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return \Drupal\views\ViewStorageInterface
@@ -57,6 +59,6 @@ public function validateView(array $form, array &$form_state);
    *
    * @throws \Drupal\views\Plugin\views\wizard\WizardException
    */
-  public function createView(array $form, array &$form_state);
+  public function createView(array $form, FormStateInterface $form_state);
 
 }
diff --git a/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
index 1ba7c23..3c55b1a 100644
--- a/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
+++ b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\wizard;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Entity\View;
 use Drupal\views\Views;
 use Drupal\views_ui\ViewUI;
@@ -214,7 +215,7 @@ public function getSorts() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $style_options = Views::fetchPluginNames('style', 'normal', array($this->base_table));
     $feed_row_options = Views::fetchPluginNames('row', 'feed', array($this->base_table));
     $path_prefix = url(NULL, array('absolute' => TRUE));
@@ -461,8 +462,8 @@ public function buildForm(array $form, array &$form_state) {
    * the results of this function for any other purpose besides deciding how to
    * build the next version of the form.
    *
-   * @param $form_state
-   *   The  standard associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param $parents
    *   An array of parent keys that point to the part of the submitted form
    *   values that are expected to contain the element's value (in the case where
@@ -524,12 +525,12 @@ public static function getSelected($form_state, $parents, $default_value, $eleme
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    * @param string $type
    *   The display ID (e.g. 'page' or 'block').
    */
-  protected function buildFormStyle(array &$form, array &$form_state, $type) {
+  protected function buildFormStyle(array &$form, FormStateInterface $form_state, $type) {
     $style_form = &$form['displays'][$type]['options']['style'];
     $style = $style_form['style_plugin']['#default_value'];
     $style_plugin = Views::pluginManager('style')->createInstance($style);
@@ -578,7 +579,7 @@ protected function rowStyleOptions() {
    * By default, this adds "of type" and "tagged with" filters (when they are
    * available).
    */
-  protected function buildFilters(&$form, &$form_state) {
+  protected function buildFilters(&$form, FormStateInterface $form_state) {
     module_load_include('inc', 'views_ui', 'admin');
 
     $bundles = entity_get_bundles($this->entityTypeId);
@@ -608,7 +609,7 @@ protected function buildFilters(&$form, &$form_state) {
    *
    * By default, this adds a "sorted by [date]" filter (when it is available).
    */
-  protected function buildSorts(&$form, &$form_state) {
+  protected function buildSorts(&$form, FormStateInterface $form_state) {
     $sorts = array(
       'none' => t('Unsorted'),
     );
@@ -641,7 +642,7 @@ protected function buildSorts(&$form, &$form_state) {
    * @return \Drupal\views_ui\ViewUI
    *   The instantiated view UI object.
    */
-  protected function instantiateView($form, &$form_state) {
+  protected function instantiateView($form, FormStateInterface $form_state) {
     // Build the basic view properties and create the view.
     $values = array(
       'id' => $form_state['values']['id'],
@@ -822,7 +823,7 @@ protected function defaultDisplayOptions() {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
@@ -848,14 +849,14 @@ protected function defaultDisplayFilters($form, $form_state) {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
    *   An array of filter arrays keyed by ID. A sort array contains the options
    *   accepted by a filter handler.
    */
-  protected function defaultDisplayFiltersUser(array $form, array &$form_state) {
+  protected function defaultDisplayFiltersUser(array $form, FormStateInterface $form_state) {
     $filters = array();
 
     if (!empty($form_state['values']['show']['type']) && $form_state['values']['show']['type'] != 'all') {
@@ -907,7 +908,7 @@ protected function defaultDisplayFiltersUser(array $form, array &$form_state) {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
@@ -933,7 +934,7 @@ protected function defaultDisplaySorts($form, $form_state) {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
@@ -981,13 +982,13 @@ protected function defaultDisplaySortsUser($form, $form_state) {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
    *   Returns an array of display options.
    */
-  protected function pageDisplayOptions(array $form, array &$form_state) {
+  protected function pageDisplayOptions(array $form, FormStateInterface $form_state) {
     $display_options = array();
     $page = $form_state['values']['page'];
     $display_options['title'] = $page['title'];
@@ -1027,13 +1028,13 @@ protected function pageDisplayOptions(array $form, array &$form_state) {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
    *   Returns an array of display options.
    */
-  protected function blockDisplayOptions(array $form, array &$form_state) {
+  protected function blockDisplayOptions(array $form, FormStateInterface $form_state) {
     $display_options = array();
     $block = $form_state['values']['block'];
     $display_options['title'] = $block['title'];
@@ -1049,7 +1050,7 @@ protected function blockDisplayOptions(array $form, array &$form_state) {
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    *
    * @return array
@@ -1143,7 +1144,7 @@ protected function setOverrideOptions(array $options, DisplayPluginBase $display
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    * @param bool $unset
    *   Should the view be removed from the list of validated views.
@@ -1151,7 +1152,7 @@ protected function setOverrideOptions(array $options, DisplayPluginBase $display
    * @return \Drupal\views_ui\ViewUI $view
    *   The validated view object.
    */
-  protected function retrieveValidatedView(array $form, array &$form_state, $unset = TRUE) {
+  protected function retrieveValidatedView(array $form, FormStateInterface $form_state, $unset = TRUE) {
     // @todo Figure out why all this hashing is done. Wouldn't it be easier to
     //   store a single entry and that's it?
     $key = hash('sha256', serialize($form_state['values']));
@@ -1167,12 +1168,12 @@ protected function retrieveValidatedView(array $form, array &$form_state, $unset
    *
    * @param array $form
    *   The full wizard form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the wizard form.
    * @param \Drupal\views_ui\ViewUI $view
    *   The validated view object.
    */
-  protected function setValidatedView(array $form, array &$form_state, ViewUI $view) {
+  protected function setValidatedView(array $form, FormStateInterface $form_state, ViewUI $view) {
     $key = hash('sha256', serialize($form_state['values']));
     $this->validated_views[$key] = $view;
   }
@@ -1182,7 +1183,7 @@ protected function setValidatedView(array $form, array &$form_state, ViewUI $vie
    *
    * Instantiates the view from the form submission and validates its values.
    */
-  public function validateView(array $form, array &$form_state) {
+  public function validateView(array $form, FormStateInterface $form_state) {
     $view = $this->instantiateView($form, $form_state);
     $errors = $view->getExecutable()->validate();
 
@@ -1196,7 +1197,7 @@ public function validateView(array $form, array &$form_state) {
   /**
    * {@inheritDoc}
    */
-  public function createView(array $form, array &$form_state) {
+  public function createView(array $form, FormStateInterface $form_state) {
     $view = $this->retrieveValidatedView($form, $form_state);
     if (empty($view)) {
       throw new WizardException('Attempted to create a view with values that have not been validated.');
diff --git a/core/modules/views/src/Tests/Handler/AreaEntityTest.php b/core/modules/views/src/Tests/Handler/AreaEntityTest.php
index ac62de1..f66a137 100644
--- a/core/modules/views/src/Tests/Handler/AreaEntityTest.php
+++ b/core/modules/views/src/Tests/Handler/AreaEntityTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Tests\Handler;
 
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\FormState;
 use Drupal\views\Tests\ViewTestBase;
 use Drupal\views\Views;
 
@@ -121,7 +122,7 @@ public function testEntityArea() {
 
     // Test the available view mode options.
     $form = array();
-    $form_state = array();
+    $form_state = new FormState();
     $form_state['type'] = 'header';
     $view->display_handler->getHandler('header', 'entity_entity_test')->buildOptionsForm($form, $form_state);
     $this->assertTrue(isset($form['view_mode']['#options']['test']), 'Ensure that the test view mode is available.');
diff --git a/core/modules/views/src/Tests/Plugin/DisplayPageTest.php b/core/modules/views/src/Tests/Plugin/DisplayPageTest.php
index 0067ce3..97e5cb9 100644
--- a/core/modules/views/src/Tests/Plugin/DisplayPageTest.php
+++ b/core/modules/views/src/Tests/Plugin/DisplayPageTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Tests\Plugin;
 
+use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\views\Views;
 use Drupal\views\Tests\ViewUnitTestBase;
 use Symfony\Component\HttpFoundation\Request;
@@ -32,7 +33,7 @@ class DisplayPageTest extends ViewUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'user', 'menu_link', 'field', 'entity');
+  public static $modules = array('system', 'user', 'field', 'entity');
 
   /**
    * The router dumper to get all routes.
@@ -49,13 +50,13 @@ protected function setUp() {
 
     // Setup the needed tables in order to make the drupal router working.
     $this->installSchema('system', array('url_alias'));
-    $this->installSchema('menu_link', 'menu_links');
   }
 
   /**
    * Checks the behavior of the page for access denied/not found behaviors.
    */
   public function testPageResponses() {
+    \Drupal::currentUser()->setAccount(new AnonymousUserSession());
     $subrequest = Request::create('/test_page_display_403', 'GET');
     $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
     $this->assertEqual($response->getStatusCode(), 403);
diff --git a/core/modules/views/src/Tests/Plugin/RowEntityTest.php b/core/modules/views/src/Tests/Plugin/RowEntityTest.php
index e422d96..6111f42 100644
--- a/core/modules/views/src/Tests/Plugin/RowEntityTest.php
+++ b/core/modules/views/src/Tests/Plugin/RowEntityTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Tests\Plugin;
 
+use Drupal\Core\Form\FormState;
 use Drupal\views\Views;
 use Drupal\views\Tests\ViewUnitTestBase;
 
@@ -59,7 +60,7 @@ public function testEntityRow() {
 
     // Tests the available view mode options.
     $form = array();
-    $form_state = array();
+    $form_state = new FormState();
     $form_state['view'] = $view->storage;
     $view->rowPlugin->buildOptionsForm($form, $form_state);
 
diff --git a/core/modules/views/src/Tests/Wizard/MenuTest.php b/core/modules/views/src/Tests/Wizard/MenuTest.php
index 3e9b8be..a245f57 100644
--- a/core/modules/views/src/Tests/Wizard/MenuTest.php
+++ b/core/modules/views/src/Tests/Wizard/MenuTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views\Tests\Wizard;
 
+use Drupal\Component\Utility\String;
+
 /**
  * Tests the ability of the views wizard to put views in a menu.
  *
@@ -39,15 +41,14 @@ function testMenus() {
     $this->assertLinkByHref(url($view['page[path]']));
 
     // Make sure the link is associated with the main menu.
-    $links = menu_load_links('main');
-    $found = FALSE;
-    foreach ($links as $link) {
-      if ($link['link_path'] == $view['page[path]']) {
-        $found = TRUE;
-        break;
-      }
-    }
-    $this->assertTrue($found, t('Found a link to %path in the main menu', array('%path' => $view['page[path]'])));
+    /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+    $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+    /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
+    $link = $menu_link_manager->createInstance('views_view:views.' . $view['id'] . '.page_1');
+    $url = $link->getUrlObject();
+    $this->assertEqual($url->getRouteName(), 'view.' . $view['id'] . '.page_1', String::format('Found a link to %path in the main menu', array('%path' => $view['page[path]'])));
+    $metadata = $link->getMetaData();
+    $this->assertEqual(array('view_id' => $view['id'], 'display_id' => 'page_1'), $metadata);
   }
 
 }
diff --git a/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php b/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php
index 37880d4..a121e70 100644
--- a/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php
+++ b/core/modules/views/src/Tests/Wizard/WizardPluginBaseUnitTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Tests\Wizard;
 
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Language\Language;
 use Drupal\views\Tests\ViewUnitTestBase;
 use Drupal\views_ui\ViewUI;
@@ -50,7 +51,7 @@ protected function setUp() {
    */
   public function testCreateView() {
     $form = array();
-    $form_state = array();
+    $form_state = new FormState();
     $form = $this->wizard->buildForm($form, $form_state);
     $random_id = strtolower($this->randomName());
     $random_label = $this->randomName();
diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php
index ad8e801..c7e810b 100644
--- a/core/modules/views/src/ViewExecutable.php
+++ b/core/modules/views/src/ViewExecutable.php
@@ -1509,17 +1509,16 @@ public function attachDisplays() {
   }
 
   /**
-   * Returns default menu links from the view and the named display handler.
+   * Returns menu links from the view and the named display handler.
    *
    * @param string $display_id
    *   A display ID.
-   * @param array $links
-   *   An array of default menu link items passed from
-   *   views_menu_link_defaults_alter().
    *
    * @return array|bool
+   *   The generated menu links for this view and display, FALSE if the call
+   *   to ::setDisplay failed.
    */
-  public function executeHookMenuLinkDefaults($display_id = NULL, &$links = array()) {
+  public function getMenuLinks($display_id = NULL) {
     // Prepare the view with the information we have. This was probably already
     // called, but it's good to be safe.
     if (!$this->setDisplay($display_id)) {
@@ -1528,7 +1527,7 @@ public function executeHookMenuLinkDefaults($display_id = NULL, &$links = array(
 
     // Execute the hook.
     if (isset($this->display_handler)) {
-      return $this->display_handler->executeHookMenuLinkDefaults($links);
+      return $this->display_handler->getMenuLinks();
     }
   }
 
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml
index 8ef1774..840d874 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display.yml
@@ -32,6 +32,7 @@ display:
     display_title: Block
     id: block_1
     position: 2
+    provider: block
   default:
     display_options:
       access:
@@ -91,3 +92,6 @@ display:
 label: ''
 id: test_display
 tag: ''
+dependencies:
+  module:
+    - block
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_invalid.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_invalid.yml
index fa7f524..638c3f5 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_invalid.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_invalid.yml
@@ -30,6 +30,10 @@ display:
     id: block_1
     display_title: Block
     position: 1
+    provider: block
 label: ''
 id: test_display_invalid
 tag: ''
+dependencies:
+  module:
+    - block
diff --git a/core/modules/views/tests/modules/views_test_data/src/Form/ViewsTestDataElementForm.php b/core/modules/views/tests/modules/views_test_data/src/Form/ViewsTestDataElementForm.php
index 8088559..27f7160 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Form/ViewsTestDataElementForm.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Form/ViewsTestDataElementForm.php
@@ -7,6 +7,7 @@
 namespace Drupal\views_test_data\Form;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Simple form page callback to test the view element.
@@ -23,7 +24,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['view'] = array(
       '#type' => 'view',
       '#name' => 'test_view',
@@ -37,7 +38,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php
index 93254b8..e61997e 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/area/TestExample.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_test_data\Plugin\views\area;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\area\AreaPluginBase;
 
 /**
@@ -31,7 +32,7 @@ public function defineOptions() {
   /**
    * Overrides Drupal\views\Plugin\views\area\AreaPluginBase::buildOptionsForm()
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
     $this->globalTokenForm($form, $form_state);
   }
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display/DisplayTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display/DisplayTest.php
index 1447c67..ca9b746 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display/DisplayTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display/DisplayTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_test_data\Plugin\views\display;
 
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 
 /**
@@ -74,7 +75,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     switch ($form_state['section']) {
@@ -93,7 +94,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::validateOptionsForm().
    */
-  public function validateOptionsForm(&$form, &$form_state) {
+  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
     parent::validateOptionsForm($form, $form_state);
     watchdog('views', $form_state['values']['test_option']);
     switch ($form_state['section']) {
@@ -108,7 +109,7 @@ public function validateOptionsForm(&$form, &$form_state) {
   /**
    * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::submitOptionsForm().
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
     switch ($form_state['section']) {
       case 'test_option':
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display_extender/DisplayExtenderTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display_extender/DisplayExtenderTest.php
index b13a2f8..e7a35ea 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display_extender/DisplayExtenderTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/display_extender/DisplayExtenderTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_test_data\Plugin\views\display_extender;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase;
 
 /**
@@ -61,7 +62,7 @@ public function optionsSummary(&$categories, &$options) {
   /**
    * Overrides Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     switch ($form_state['section']) {
       case 'test_extender_test_option':
         $form['#title'] .= t('Test option');
@@ -77,7 +78,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   /**
    * Overrides Drupal\views\Plugin\views\display\DisplayExtenderPluginBase::submitOptionsForm().
    */
-  public function submitOptionsForm(&$form, &$form_state) {
+  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
     parent::submitOptionsForm($form, $form_state);
     switch ($form_state['section']) {
       case 'test_extender_test_option':
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/filter/FilterTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/filter/FilterTest.php
index 3abcc16..c7e00c8 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/filter/FilterTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/filter/FilterTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_test_data\Plugin\views\filter;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 
 /**
@@ -31,7 +32,7 @@ protected function defineOptions() {
    *
    * @return array
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['test_enable'] = array(
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/query/QueryTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/query/QueryTest.php
index 77a9607..5a1b61b 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/query/QueryTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/query/QueryTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_test_data\Plugin\views\query;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\query\QueryPluginBase;
 use Drupal\views\Plugin\views\join\JoinPluginBase;
 use Drupal\views\ViewExecutable;
@@ -39,7 +40,7 @@ protected function defineOptions() {
   /**
    * Implements \Drupal\views\Plugin\views\query\QueryPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['test_setting'] = array(
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/row/RowTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/row/RowTest.php
index e6edd02..cb759a3 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/row/RowTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/row/RowTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_test_data\Plugin\views\row;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\row\RowPluginBase;
 
 /**
@@ -44,7 +45,7 @@ protected function defineOptions() {
   /**
    * Overrides Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['test_option'] = array(
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/style/StyleTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/style/StyleTest.php
index 02dd245..748dbd2 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/style/StyleTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/style/StyleTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_test_data\Plugin\views\style;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\style\StylePluginBase;
 
 /**
@@ -52,7 +53,7 @@ protected function defineOptions() {
   /**
    * Overrides Drupal\views\Plugin\views\style\StylePluginBase::buildOptionsForm().
    */
-  public function buildOptionsForm(&$form, &$form_state) {
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
     $form['test_option'] = array(
diff --git a/core/modules/views/tests/src/Entity/ViewTest.php b/core/modules/views/tests/src/Entity/ViewTest.php
index 520c6a2..6bfdd5b 100644
--- a/core/modules/views/tests/src/Entity/ViewTest.php
+++ b/core/modules/views/tests/src/Entity/ViewTest.php
@@ -50,6 +50,7 @@ public function testCalculateDependencies($values, $deps) {
   }
 
   public function calculateDependenciesProvider(){
+    $handler['display']['default']['provider'] = 'block';
     $handler['display']['default']['display_options']['fields']['example']['dependencies'] = array();
     $handler['display']['default']['display_options']['fields']['example2']['dependencies']['module'] = array('views', 'field');
     $handler['display']['default']['display_options']['fields']['example3']['dependencies']['module'] = array('views', 'image');
@@ -60,7 +61,7 @@ public function calculateDependenciesProvider(){
 
     return array(
       array(array(), array('node', 'views')),
-      array($handler, array('field', 'image', 'node', 'views')),
+      array($handler, array('block', 'field', 'image', 'node', 'views')),
       array($plugin, array('field', 'image', 'node', 'views')),
     );
   }
diff --git a/core/modules/views/views.links.menu.yml b/core/modules/views/views.links.menu.yml
new file mode 100644
index 0000000..6188677
--- /dev/null
+++ b/core/modules/views/views.links.menu.yml
@@ -0,0 +1,4 @@
+views_view:
+  class: Drupal\views\Plugin\Menu\ViewsMenuLink
+  form_class: Drupal\views\Plugin\Menu\Form\ViewsMenuLinkForm
+  deriver: \Drupal\views\Plugin\Derivative\ViewsMenuLink
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index d9d9805..6cda6a9 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -12,6 +12,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Database\Query\AlterableInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -305,23 +306,6 @@ function views_permission() {
 }
 
 /**
- * Implements hook_menu_link_defaults_alter().
- */
-function views_menu_link_defaults_alter(array &$links) {
-  // @todo Decide what to do with all the crazy logic in views_menu_alter() in
-  // https://drupal.org/node/2107533.
-  $views = Views::getApplicableViews('uses_hook_menu');
-  foreach ($views as $data) {
-    /** @var \Drupal\views\ViewExecutable $view */
-    list($view, $display_id) = $data;
-    $result = $view->executeHookMenuLinkDefaults($display_id, $links);
-    foreach ($result as $link_id => $link) {
-      $links[$link_id] = $link;
-    }
-  }
-}
-
-/**
  * Implements hook_page_alter().
  */
 function views_page_alter(&$page) {
@@ -877,7 +861,7 @@ function views_pre_render_views_form_views_form($element) {
  * Since the exposed form is a GET form, we don't want it to send a wide
  * variety of information.
  */
-function views_form_views_exposed_form_alter(&$form, &$form_state) {
+function views_form_views_exposed_form_alter(&$form, FormStateInterface $form_state) {
   $form['form_build_id']['#access'] = FALSE;
   $form['form_token']['#access'] = FALSE;
   $form['form_id']['#access'] = FALSE;
@@ -1012,7 +996,7 @@ function views_get_view_result($name, $display_id = NULL) {
 /**
  * Validation callback for query tags.
  */
-function views_element_validate_tags($element, &$form_state) {
+function views_element_validate_tags($element, FormStateInterface $form_state) {
   $values = array_map('trim', explode(',', $element['#value']));
   foreach ($values as $value) {
     if (preg_match("/[^a-z_]/", $value)) {
diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc
index 1bd8636..504e93c 100644
--- a/core/modules/views_ui/admin.inc
+++ b/core/modules/views_ui/admin.inc
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Tags;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
 
@@ -120,7 +121,7 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa
 /**
  * Processes a non-JavaScript fallback submit button to limit its validation errors.
  */
-function views_ui_add_limited_validation($element, &$form_state) {
+function views_ui_add_limited_validation($element, FormStateInterface $form_state) {
   // Retrieve the AJAX triggering element so we can determine its parents. (We
   // know it's at the same level of the complete form array as the submit
   // button, so all we have to do to find it is swap out the submit button's
@@ -158,7 +159,7 @@ function views_ui_add_limited_validation($element, &$form_state) {
  * be refreshed by AJAX, based on information stored in the corresponding
  * submit button form element.
  */
-function views_ui_add_ajax_wrapper($element, &$form_state) {
+function views_ui_add_ajax_wrapper($element, FormStateInterface $form_state) {
   // Don't add the wrapper <div> if the same one was already inserted on this
   // form.
   if (empty($element['#views_ui_ajax_data']['duplicate_wrapper'])) {
@@ -202,7 +203,7 @@ function views_ui_ajax_update_form($form, $form_state) {
 /**
  * Non-Javascript fallback for updating the add view form.
  */
-function views_ui_nojs_submit($form, &$form_state) {
+function views_ui_nojs_submit($form, FormStateInterface $form_state) {
   $form_state['rebuild'] = TRUE;
 }
 
@@ -220,7 +221,7 @@ function views_ui_nojs_submit($form, &$form_state) {
  *
  * @see taxonomy_autocomplete_validate()
  */
-function views_ui_taxonomy_autocomplete_validate($element, &$form_state) {
+function views_ui_taxonomy_autocomplete_validate($element, FormStateInterface $form_state) {
   $value = array();
   if ($tags = $element['#value']) {
     // Get the machine names of the vocabularies we will search, keyed by the
@@ -261,7 +262,7 @@ function views_ui_taxonomy_autocomplete_validate($element, &$form_state) {
  * change whether this info is stored on the default display or on
  * the current display.
  */
-function views_ui_standard_display_dropdown(&$form, &$form_state, $section) {
+function views_ui_standard_display_dropdown(&$form, FormStateInterface $form_state, $section) {
   $view = $form_state['view'];
   $display_id = $form_state['display_id'];
   $executable = $view->getExecutable();
@@ -352,7 +353,7 @@ function views_ui_build_form_path($form_state) {
  * @see _form_builder_handle_input_element()
  * @see _form_button_was_clicked()
  */
-function views_ui_form_button_was_clicked($element, &$form_state) {
+function views_ui_form_button_was_clicked($element, FormStateInterface $form_state) {
   $process_input = empty($element['#disabled']) && ($form_state['programmed'] || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
   if ($process_input && !isset($form_state['triggering_element']) && !empty($element['#is_button']) && isset($form_state['input'][$element['#name']]) && isset($element['#values']) && in_array($form_state['input'][$element['#name']], $element['#values'], TRUE)) {
     $form_state['triggering_element'] = $element;
diff --git a/core/modules/views_ui/src/Form/AdvancedSettingsForm.php b/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
index 9ba103d..b84eb29 100644
--- a/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
+++ b/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 
 /**
@@ -25,7 +26,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
     $config = $this->config('views.settings');
@@ -90,7 +91,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('views.settings')
       ->set('skip_cache', $form_state['values']['skip_cache'])
       ->set('sql_signature', $form_state['values']['sql_signature'])
diff --git a/core/modules/views_ui/src/Form/Ajax/AddHandler.php b/core/modules/views_ui/src/Form/Ajax/AddHandler.php
index 95b3fd0..4b69e93 100644
--- a/core/modules/views_ui/src/Form/Ajax/AddHandler.php
+++ b/core/modules/views_ui/src/Form/Ajax/AddHandler.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\Views;
@@ -48,7 +49,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
     $type = $form_state['type'];
diff --git a/core/modules/views_ui/src/Form/Ajax/Analyze.php b/core/modules/views_ui/src/Form/Ajax/Analyze.php
index 41a7d94..23840cb 100644
--- a/core/modules/views_ui/src/Form/Ajax/Analyze.php
+++ b/core/modules/views_ui/src/Form/Ajax/Analyze.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 use Drupal\views_ui\ViewUI;
 use Drupal\views\Analyzer;
@@ -33,7 +34,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
 
     $form['#title'] = $this->t('View analysis');
@@ -57,7 +58,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     /** @var $view \Drupal\views_ui\ViewUI */
     $view = $form_state['view'];
     $form_state['redirect_route'] = $view->urlInfo('edit-form');
diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
index 8533e69..066efe7 100644
--- a/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
+++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandler.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
@@ -50,7 +51,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
     $type = $form_state['type'];
@@ -189,7 +190,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state['handler']->validateOptionsForm($form['options'], $form_state);
 
     if (form_get_errors($form_state)) {
@@ -200,7 +201,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Run it through the handler's submit function.
     $form_state['handler']->submitOptionsForm($form['options'], $form_state);
     $item = $form_state['handler']->options;
@@ -261,7 +262,7 @@ public function submitForm(array &$form, array &$form_state) {
   /**
    * Submit handler for removing an item from a view
    */
-  public function remove(&$form, &$form_state) {
+  public function remove(&$form, FormStateInterface $form_state) {
     // Store the item back on the view
     list($was_defaulted, $is_defaulted) = $form_state['view']->getOverrideValues($form, $form_state);
     $executable = $form_state['view']->getExecutable();
diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php
index 02ed828..16bc230 100644
--- a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php
+++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\ViewExecutable;
 
@@ -49,7 +50,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
     $type = $form_state['type'];
@@ -92,14 +93,14 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state['handler']->validateExtraOptionsForm($form['options'], $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Run it through the handler's submit function.
     $form_state['handler']->submitExtraOptionsForm($form['options'], $form_state);
     $item = $form_state['handler']->options;
diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerGroup.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerGroup.php
index f00d26f..fba13ea 100644
--- a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerGroup.php
+++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerGroup.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\ViewExecutable;
@@ -50,7 +51,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
     $type = $form_state['type'];
@@ -95,7 +96,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $item = &$form_state['handler']->options;
     $type = $form_state['type'];
 
diff --git a/core/modules/views_ui/src/Form/Ajax/Display.php b/core/modules/views_ui/src/Form/Ajax/Display.php
index c2dbad6..c653fc1 100644
--- a/core/modules/views_ui/src/Form/Ajax/Display.php
+++ b/core/modules/views_ui/src/Form/Ajax/Display.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewStorageInterface;
 
 /**
@@ -35,9 +36,9 @@ public function getFormKey() {
    *   $form_state['type'].
    */
   public function getFormState(ViewStorageInterface $view, $display_id, $js) {
-    return array(
-      'section' => $this->type,
-    ) + parent::getFormState($view, $display_id, $js);
+    $form_state = parent::getFormState($view, $display_id, $js);
+    $form_state['section'] = $this->type;
+    return $form_state;
   }
 
   /**
@@ -58,7 +59,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
 
@@ -95,7 +96,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state['view']->getExecutable()->displayHandlers->get($form_state['display_id'])->validateOptionsForm($form['options'], $form_state);
 
     if (form_get_errors($form_state)) {
@@ -106,7 +107,7 @@ public function validateForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $form_state['view']->getExecutable()->displayHandlers->get($form_state['display_id'])->submitOptionsForm($form['options'], $form_state);
 
     $form_state['view']->cacheSet();
diff --git a/core/modules/views_ui/src/Form/Ajax/EditDetails.php b/core/modules/views_ui/src/Form/Ajax/EditDetails.php
index 6269af1..f6684a2 100644
--- a/core/modules/views_ui/src/Form/Ajax/EditDetails.php
+++ b/core/modules/views_ui/src/Form/Ajax/EditDetails.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 use Drupal\views_ui\ViewUI;
 
@@ -32,7 +33,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
 
     $form['#title'] = $this->t('Name and description');
@@ -73,7 +74,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     foreach ($form_state['values'] as $key => $value) {
       // Only save values onto the view if they're actual view properties
diff --git a/core/modules/views_ui/src/Form/Ajax/Rearrange.php b/core/modules/views_ui/src/Form/Ajax/Rearrange.php
index 86b3274..5e3d709 100644
--- a/core/modules/views_ui/src/Form/Ajax/Rearrange.php
+++ b/core/modules/views_ui/src/Form/Ajax/Rearrange.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\ViewExecutable;
 
@@ -47,7 +48,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
     $type = $form_state['type'];
@@ -134,7 +135,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $types = ViewExecutable::getHandlerTypes();
     $display = &$form_state['view']->getExecutable()->displayHandlers->get($form_state['display_id']);
 
diff --git a/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php b/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php
index e15e440..54ba06e 100644
--- a/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php
+++ b/core/modules/views_ui/src/Form/Ajax/RearrangeFilter.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui\Form\Ajax;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views_ui\ViewUI;
 use Drupal\views\ViewExecutable;
 
@@ -33,7 +34,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
     $type = 'filter';
@@ -213,7 +214,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $types = ViewExecutable::getHandlerTypes();
     $display = &$form_state['view']->getExecutable()->displayHandlers->get($form_state['display_id']);
     $remember_groups = array();
diff --git a/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php b/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php
index 61e5693..d9bfd29 100644
--- a/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php
+++ b/core/modules/views_ui/src/Form/Ajax/ReorderDisplays.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Form\Ajax;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views_ui\ViewUI;
 
 /**
@@ -31,7 +32,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     /** @var $view \Drupal\views\ViewStorageInterface */
     $view = $form_state['view'];
     $display_id = $form_state['display_id'];
@@ -148,7 +149,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     /** @var $view \Drupal\views_ui\ViewUI */
     $view = $form_state['view'];
     $order = array();
diff --git a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
index f7d4b86..f905060 100644
--- a/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
+++ b/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php
@@ -8,6 +8,8 @@
 namespace Drupal\views_ui\Form\Ajax;
 
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\Ajax;
 use Drupal\Core\Ajax\AjaxResponse;
@@ -63,7 +65,7 @@ protected function setType($type) {
   public function getFormState(ViewStorageInterface $view, $display_id, $js) {
     // $js may already have been converted to a Boolean.
     $ajax = is_string($js) ? $js === 'ajax' : $js;
-    return array(
+    return new FormState(array(
       'form_id' => $this->getFormId(),
       'form_key' => $this->getFormKey(),
       'ajax' => $ajax,
@@ -76,7 +78,7 @@ public function getFormState(ViewStorageInterface $view, $display_id, $js) {
         'args' => array(),
         'callback_object' => $this,
       ),
-    );
+    ));
   }
 
   /**
@@ -179,13 +181,13 @@ public function getForm(ViewStorageInterface $view, $display_id, $js) {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/modules/views_ui/src/Form/Ajax/ViewsFormInterface.php b/core/modules/views_ui/src/Form/Ajax/ViewsFormInterface.php
index d109ea3..8bc8adf 100644
--- a/core/modules/views_ui/src/Form/Ajax/ViewsFormInterface.php
+++ b/core/modules/views_ui/src/Form/Ajax/ViewsFormInterface.php
@@ -32,8 +32,8 @@ public function getFormKey();
    *   If this is an AJAX form, it will be the string 'ajax'. Otherwise, it will
    *   be 'nojs'. This determines the response.
    *
-   * @return array
-   *   An associative array containing the current state of the form.
+   * @return \Drupal\Core\Form\FormStateInterface
+   *   The current state of the form.
    */
   public function getFormState(ViewStorageInterface $view, $display_id, $js);
 
diff --git a/core/modules/views_ui/src/Form/BasicSettingsForm.php b/core/modules/views_ui/src/Form/BasicSettingsForm.php
index f898f9a..6b15d79 100644
--- a/core/modules/views_ui/src/Form/BasicSettingsForm.php
+++ b/core/modules/views_ui/src/Form/BasicSettingsForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui\Form;
 
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form builder for the admin display defaults page.
@@ -24,7 +25,7 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
 
     $config = $this->config('views.settings');
@@ -126,7 +127,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     $this->config('views.settings')
       ->set('ui.show.master_display', $form_state['values']['ui_show_master_display'])
       ->set('ui.show.advanced_column', $form_state['values']['ui_show_advanced_column'])
diff --git a/core/modules/views_ui/src/Form/BreakLockForm.php b/core/modules/views_ui/src/Form/BreakLockForm.php
index e981a48..b95b65e 100644
--- a/core/modules/views_ui/src/Form/BreakLockForm.php
+++ b/core/modules/views_ui/src/Form/BreakLockForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\TempStoreFactory;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -98,7 +99,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     if (!$this->tempStore->getMetadata($this->entity->id())) {
       $form['message']['#markup'] = $this->t('There is no lock on view %name to break.', array('%name' => $this->entity->id()));
       return $form;
@@ -109,7 +110,7 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $this->tempStore->delete($this->entity->id());
     $form_state['redirect_route'] = $this->entity->urlInfo('edit-form');
     drupal_set_message($this->t('The lock has been broken and you may now edit this view.'));
diff --git a/core/modules/views_ui/src/ViewAddForm.php b/core/modules/views_ui/src/ViewAddForm.php
index fac46e3..9c2c662 100644
--- a/core/modules/views_ui/src/ViewAddForm.php
+++ b/core/modules/views_ui/src/ViewAddForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\wizard\WizardPluginBase;
 use Drupal\views\Plugin\views\wizard\WizardException;
 use Drupal\views\Plugin\ViewsPluginManager;
@@ -53,7 +54,7 @@ protected function prepareEntity() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $form['#attached']['css'] = static::getAdminCSS();
     $form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
     $form['#attributes']['class'] = array('views-admin');
@@ -145,7 +146,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     $actions['submit']['#value'] = $this->t('Save and edit');
 
@@ -163,7 +164,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     $wizard_type = $form_state['values']['show']['wizard_key'];
     $wizard_instance = $this->wizardManager->createInstance($wizard_type);
     $form_state['wizard'] = $wizard_instance->getPluginDefinition();
@@ -180,7 +181,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     try {
       /** @var $wizard \Drupal\views\Plugin\views\wizard\WizardInterface */
       $wizard = $form_state['wizard_instance'];
@@ -202,10 +203,10 @@ public function submit(array $form, array &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function cancel(array $form, array &$form_state) {
+  public function cancel(array $form, FormStateInterface $form_state) {
     $form_state['redirect_route']['route_name'] = 'views_ui.list';
   }
 
diff --git a/core/modules/views_ui/src/ViewDeleteForm.php b/core/modules/views_ui/src/ViewDeleteForm.php
index fa446ee..555d1a8 100644
--- a/core/modules/views_ui/src/ViewDeleteForm.php
+++ b/core/modules/views_ui/src/ViewDeleteForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui;
 
 use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
@@ -39,13 +40,13 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     $this->entity->delete();
     drupal_set_message($this->t('View %name deleted',array('%name' => $this->entity->label())));
 
-    $form_state['redirect_route'] = $this->getCancelUrl();
+    $form_state->setRedirect($this->getCancelUrl());
   }
 
 }
diff --git a/core/modules/views_ui/src/ViewDuplicateForm.php b/core/modules/views_ui/src/ViewDuplicateForm.php
index c46101a..b4b5eef 100644
--- a/core/modules/views_ui/src/ViewDuplicateForm.php
+++ b/core/modules/views_ui/src/ViewDuplicateForm.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\views_ui;
 
+use Drupal\Core\Form\FormStateInterface;
+
 /**
  * Form controller for the Views duplicate form.
  */
@@ -22,7 +24,7 @@ protected function prepareEntity() {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     parent::form($form, $form_state);
 
     $form['#title'] = $this->t('Duplicate of @label', array('@label' => $this->entity->label()));
@@ -52,7 +54,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions['submit'] = array(
       '#type' => 'submit',
       '#value' => $this->t('Duplicate'),
@@ -66,7 +68,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     $original = parent::submit($form, $form_state);
     $this->entity = $original->createDuplicate();
     $this->entity->set('id', $form_state['values']['id']);
diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php
index ebb2736..677ef1e 100644
--- a/core/modules/views_ui/src/ViewEditForm.php
+++ b/core/modules/views_ui/src/ViewEditForm.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Datetime\Date as DateFormatter;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\user\TempStoreFactory;
 use Drupal\views\Views;
@@ -76,7 +77,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $view = $this->entity;
     $display_id = $this->displayID;
     // Do not allow the form to be cached, because $form_state['view'] can become
@@ -230,7 +231,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $actions = parent::actions($form, $form_state);
     unset($actions['delete']);
 
@@ -251,7 +252,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function validate(array $form, array &$form_state) {
+  public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
     $view = $this->entity;
@@ -268,7 +269,7 @@ public function validate(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, array &$form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
     parent::submit($form, $form_state);
 
     $view = $this->entity;
@@ -338,10 +339,10 @@ public function submit(array $form, array &$form_state) {
    *
    * @param array $form
    *   An associative array containing the structure of the form.
-   * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    */
-  public function cancel(array $form, array &$form_state) {
+  public function cancel(array $form, FormStateInterface $form_state) {
     // Remove this view from cache so edits will be lost.
     $view = $this->entity;
     $this->tempStore->delete($view->id());
@@ -576,7 +577,7 @@ public function getDisplayDetails($view, $display) {
   /**
    * Submit handler to add a restore a removed display to a view.
    */
-  public function submitDisplayUndoDelete($form, &$form_state) {
+  public function submitDisplayUndoDelete($form, FormStateInterface $form_state) {
     $view = $this->entity;
     // Create the new display
     $id = $form_state['display_id'];
@@ -597,7 +598,7 @@ public function submitDisplayUndoDelete($form, &$form_state) {
   /**
    * Submit handler to enable a disabled display.
    */
-  public function submitDisplayEnable($form, &$form_state) {
+  public function submitDisplayEnable($form, FormStateInterface $form_state) {
     $view = $this->entity;
     $id = $form_state['display_id'];
     // setOption doesn't work because this would might affect upper displays
@@ -616,7 +617,7 @@ public function submitDisplayEnable($form, &$form_state) {
   /**
    * Submit handler to disable display.
    */
-  public function submitDisplayDisable($form, &$form_state) {
+  public function submitDisplayDisable($form, FormStateInterface $form_state) {
     $view = $this->entity;
     $id = $form_state['display_id'];
     $view->getExecutable()->displayHandlers->get($id)->setOption('enabled', FALSE);
@@ -634,7 +635,7 @@ public function submitDisplayDisable($form, &$form_state) {
   /**
    * Submit handler to delete a display from a view.
    */
-  public function submitDisplayDelete($form, &$form_state) {
+  public function submitDisplayDelete($form, FormStateInterface $form_state) {
     $view = $this->entity;
     $display_id = $form_state['display_id'];
 
@@ -776,7 +777,7 @@ public function renderDisplayTop(ViewUI $view) {
    * contextual link). This handler can be added to buttons whose form submission
    * should not yet redirect to the destination.
    */
-  public function submitDelayDestination($form, &$form_state) {
+  public function submitDelayDestination($form, FormStateInterface $form_state) {
     $query = $this->requestStack->getCurrentRequest()->query;
     // @todo: Revisit this when http://drupal.org/node/1668866 is in.
     $destination = $query->get('destination');
@@ -799,7 +800,7 @@ public function submitDelayDestination($form, &$form_state) {
   /**
    * Submit handler to duplicate a display for a view.
    */
-  public function submitDisplayDuplicate($form, &$form_state) {
+  public function submitDisplayDuplicate($form, FormStateInterface $form_state) {
     $view = $this->entity;
     $display_id = $this->displayID;
 
@@ -826,7 +827,7 @@ public function submitDisplayDuplicate($form, &$form_state) {
   /**
    * Submit handler to add a display to a view.
    */
-  public function submitDisplayAdd($form, &$form_state) {
+  public function submitDisplayAdd($form, FormStateInterface $form_state) {
     $view = $this->entity;
     // Create the new display.
     $parents = $form_state['triggering_element']['#parents'];
@@ -848,7 +849,7 @@ public function submitDisplayAdd($form, &$form_state) {
   /**
    * Submit handler to Duplicate a display as another display type.
    */
-  public function submitDuplicateDisplayAsType($form, &$form_state) {
+  public function submitDuplicateDisplayAsType($form, FormStateInterface $form_state) {
     $view = $this->entity;
     $display_id = $this->displayID;
 
diff --git a/core/modules/views_ui/src/ViewFormBase.php b/core/modules/views_ui/src/ViewFormBase.php
index 61b872f..e9841b7 100644
--- a/core/modules/views_ui/src/ViewFormBase.php
+++ b/core/modules/views_ui/src/ViewFormBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\views_ui;
 
 use Drupal\Core\Entity\EntityForm;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
@@ -26,7 +27,7 @@
   /**
    * {@inheritdoc}
    */
-  public function init(array &$form_state) {
+  public function init(FormStateInterface $form_state) {
     parent::init($form_state);
 
     if ($display_id = \Drupal::request()->attributes->get('display_id')) {
@@ -35,7 +36,7 @@ public function init(array &$form_state) {
 
     // @todo Remove the need for this.
     form_load_include($form_state, 'inc', 'views_ui', 'admin');
-    $form_state['view'] = $this->entity;
+    $form_state->set('view', $this->entity);
   }
 
   /**
diff --git a/core/modules/views_ui/src/ViewPreviewForm.php b/core/modules/views_ui/src/ViewPreviewForm.php
index e2d2899..a8a0855 100644
--- a/core/modules/views_ui/src/ViewPreviewForm.php
+++ b/core/modules/views_ui/src/ViewPreviewForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui;
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\TempStoreFactory;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -44,7 +45,7 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function form(array $form, array &$form_state) {
+  public function form(array $form, FormStateInterface $form_state) {
     $view = $this->entity;
 
     $form['#prefix'] = '<div id="views-preview-wrapper" class="views-admin clearfix">';
@@ -100,7 +101,7 @@ public function form(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  protected function actions(array $form, array &$form_state) {
+  protected function actions(array $form, FormStateInterface $form_state) {
     $view = $this->entity;
     return array(
       '#attributes' => array(
@@ -126,7 +127,7 @@ protected function actions(array $form, array &$form_state) {
   /**
    * Form submission handler for the Preview button.
    */
-  public function submitPreview($form, &$form_state) {
+  public function submitPreview($form, FormStateInterface $form_state) {
     // Rebuild the form with a pristine $view object.
     $view = $this->entity;
     // Attempt to load the view from temp store, otherwise create a new one.
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 81f85fe..ab36fdb 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Timer;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Views;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\views\ViewExecutable;
@@ -241,7 +242,7 @@ public function isUninstalling() {
    * to apply to the default display or to the current display, and dispatches
    * control appropriately.
    */
-  public function standardSubmit($form, &$form_state) {
+  public function standardSubmit($form, FormStateInterface $form_state) {
     // Determine whether the values the user entered are intended to apply to
     // the current display or the default display.
 
@@ -296,7 +297,7 @@ public function standardSubmit($form, &$form_state) {
   /**
    * Submit handler for cancel button
    */
-  public function standardCancel($form, &$form_state) {
+  public function standardCancel($form, FormStateInterface $form_state) {
     if (!empty($this->changed) && isset($this->form_cache)) {
       unset($this->form_cache);
       $this->cacheSet();
@@ -313,7 +314,7 @@ public function standardCancel($form, &$form_state) {
    * TODO: Is the hidden op operator still here somewhere, or is that part of the
    * docblock outdated?
    */
-  public function getStandardButtons(&$form, &$form_state, $form_id, $name = NULL) {
+  public function getStandardButtons(&$form, FormStateInterface $form_state, $form_id, $name = NULL) {
     $form['actions'] = array(
       '#type' => 'actions',
     );
@@ -475,7 +476,7 @@ public function addFormToStack($key, $display_id, $type, $id = NULL, $top = FALS
   /**
    * Submit handler for adding new item(s) to a view.
    */
-  public function submitItemAdd($form, &$form_state) {
+  public function submitItemAdd($form, FormStateInterface $form_state) {
     $type = $form_state['type'];
     $types = ViewExecutable::getHandlerTypes();
     $section = $types[$type]['plural'];
diff --git a/core/profiles/standard/standard.info.yml b/core/profiles/standard/standard.info.yml
index 7029739..a1c07b2 100644
--- a/core/profiles/standard/standard.info.yml
+++ b/core/profiles/standard/standard.info.yml
@@ -14,6 +14,7 @@ dependencies:
   - comment
   - contextual
   - contact
+  - menu_link_content
   - datetime
   - block_content
   - quickedit
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index 30656be..673ddf7 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -43,16 +43,11 @@ function standard_install() {
     ->fields(array('uid' => 1, 'rid' => 'administrator'))
     ->execute();
 
-  // Create a Home link in the main menu.
-  $menu_link = entity_create('menu_link', array(
-    'link_title' => t('Home'),
-    'link_path' => '<front>',
-    'menu_name' => 'main',
-  ));
-  $menu_link->save();
-
   // Enable the Contact link in the footer menu.
-  menu_link_maintain('contact', 'enable', 'contact');
+  /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
+  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
+  $menu_link_manager->updateDefinition('contact.site_page', array('hidden' => 0));
+
   user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
   user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access site-wide contact form'));
 
@@ -78,11 +73,4 @@ function standard_install() {
 
   // Enable the admin theme.
   \Drupal::config('node.settings')->set('use_admin_theme', '1')->save();
-
-  // @todo Remove in https://www.drupal.org/node/2295129.
-  // Resave the plain_text formatter so that default filter plugins and
-  // dependencies are calculated correctly. This resolves an issue caused by the
-  // fact that filter is installed before editor but the standard profile also
-  // enables the file module.
-  entity_load('filter_format', 'plain_text')->save();
 }
diff --git a/core/profiles/standard/standard.links.menu.yml b/core/profiles/standard/standard.links.menu.yml
new file mode 100644
index 0000000..2278b21
--- /dev/null
+++ b/core/profiles/standard/standard.links.menu.yml
@@ -0,0 +1,4 @@
+standard.front_page:
+  title: 'Home'
+  route_name: '<front>'
+  menu_name: main
diff --git a/core/tests/Drupal/Tests/Core/Display/DisplayVariantTest.php b/core/tests/Drupal/Tests/Core/Display/DisplayVariantTest.php
index add47b1..4ec28d2 100644
--- a/core/tests/Drupal/Tests/Core/Display/DisplayVariantTest.php
+++ b/core/tests/Drupal/Tests/Core/Display/DisplayVariantTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Tests\Core\Display;
 
+use Drupal\Core\Form\FormState;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -142,6 +143,7 @@ public function testSubmitConfigurationForm() {
 
     $form = array();
     $label = $this->randomName();
+    $form_state = new FormState();
     $form_state['values']['label'] = $label;
     $display_variant->submitConfigurationForm($form, $form_state);
     $this->assertSame($label, $display_variant->label());
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityFormBuilderTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityFormBuilderTest.php
index 14622d2..2e7ab80 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityFormBuilderTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityFormBuilderTest.php
@@ -60,7 +60,7 @@ public function testGetForm() {
 
     $this->formBuilder->expects($this->once())
       ->method('buildForm')
-      ->with($form_controller, $this->isType('array'))
+      ->with($form_controller, $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'))
       ->will($this->returnValue('the form contents'));
 
     $entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityResolverManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityResolverManagerTest.php
index 40a000d..23bd5c9 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityResolverManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityResolverManagerTest.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityResolverManager;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\Routing\Route;
 
@@ -418,13 +419,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, EntityInterface $entity_test = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity_test = NULL) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
@@ -443,13 +444,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, $entity_test = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_test = NULL) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
@@ -465,19 +466,19 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, array &$form_state, EntityInterface $entity_test = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity_test = NULL) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, array &$form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state) {
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, array &$form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
index 4702b9d..fede0c1 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
@@ -9,6 +9,8 @@
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -26,11 +28,12 @@ class FormBuilderTest extends FormTestBase {
   public function testGetFormIdWithString() {
     $form_arg = 'foo';
 
-    $form_state = array();
+    $clean_form_state = new FormState();
+    $form_state = new FormState();
     $form_id = $this->formBuilder->getFormId($form_arg, $form_state);
 
     $this->assertSame($form_arg, $form_id);
-    $this->assertEmpty($form_state);
+    $this->assertSame($clean_form_state, $form_state);
   }
 
   /**
@@ -39,7 +42,7 @@ public function testGetFormIdWithString() {
   public function testGetFormIdWithClassName() {
     $form_arg = 'Drupal\Tests\Core\Form\TestForm';
 
-    $form_state = array();
+    $form_state = new FormState();
     $form_id = $this->formBuilder->getFormId($form_arg, $form_state);
 
     $this->assertSame('test_form', $form_id);
@@ -55,7 +58,7 @@ public function testGetFormIdWithInjectedClassName() {
 
     $form_arg = 'Drupal\Tests\Core\Form\TestFormInjected';
 
-    $form_state = array();
+    $form_state = new FormState();
     $form_id = $this->formBuilder->getFormId($form_arg, $form_state);
 
     $this->assertSame('test_form', $form_id);
@@ -70,7 +73,7 @@ public function testGetFormIdWithObject() {
 
     $form_arg = $this->getMockForm($expected_form_id);
 
-    $form_state = array();
+    $form_state = new FormState();
     $form_id = $this->formBuilder->getFormId($form_arg, $form_state);
 
     $this->assertSame($expected_form_id, $form_id);
@@ -92,7 +95,7 @@ public function testGetFormIdWithBaseForm() {
       ->method('getBaseFormId')
       ->will($this->returnValue($base_form_id));
 
-    $form_state = array();
+    $form_state = new FormState();
     $form_id = $this->formBuilder->getFormId($form_arg, $form_state);
 
     $this->assertSame($expected_form_id, $form_id);
@@ -119,11 +122,11 @@ public function testHandleFormStateResponse($class, $form_state_key) {
     $form_arg = $this->getMockForm($form_id, $expected_form);
     $form_arg->expects($this->any())
       ->method('submitForm')
-      ->will($this->returnCallback(function ($form, &$form_state) use ($response, $form_state_key) {
+      ->will($this->returnCallback(function ($form, FormStateInterface $form_state) use ($response, $form_state_key) {
         $form_state[$form_state_key] = $response;
       }));
 
-    $form_state = array();
+    $form_state = new FormState();
     try {
       $form_state['values'] = array();
       $form_state['input']['form_id'] = $form_id;
@@ -171,13 +174,13 @@ public function testHandleRedirectWithResponse() {
     $form_arg = $this->getMockForm($form_id, $expected_form);
     $form_arg->expects($this->any())
       ->method('submitForm')
-      ->will($this->returnCallback(function ($form, &$form_state) use ($response, $redirect) {
+      ->will($this->returnCallback(function ($form, FormStateInterface $form_state) use ($response, $redirect) {
         // Set both the response and the redirect.
         $form_state['response'] = $response;
         $form_state['redirect'] = $redirect;
       }));
 
-    $form_state = array();
+    $form_state = new FormState();
     try {
       $form_state['values'] = array();
       $form_state['input']['form_id'] = $form_id;
@@ -226,7 +229,7 @@ public function testGetFormWithClassString() {
     $form_id = '\Drupal\Tests\Core\Form\TestForm';
     $object = new TestForm();
     $form = array();
-    $form_state = array();
+    $form_state = new FormState();
     $expected_form = $object->buildForm($form, $form_state);
 
     $form = $this->formBuilder->getForm($form_id);
@@ -256,7 +259,7 @@ public function testBuildFormWithClassString() {
     $form_id = '\Drupal\Tests\Core\Form\TestForm';
     $object = new TestForm();
     $form = array();
-    $form_state = array();
+    $form_state = new FormState();
     $expected_form = $object->buildForm($form, $form_state);
 
     $form = $this->formBuilder->buildForm($form_id, $form_state);
@@ -273,7 +276,7 @@ public function testBuildFormWithObject() {
 
     $form_arg = $this->getMockForm($form_id, $expected_form);
 
-    $form_state = array();
+    $form_state = new FormState();
     $form = $this->formBuilder->buildForm($form_arg, $form_state);
     $this->assertFormElement($expected_form, $form, 'test');
     $this->assertSame($form_id, $form_state['build_info']['form_id']);
@@ -297,7 +300,7 @@ public function testRebuildForm() {
       ->will($this->returnValue($expected_form));
 
     // Do an initial build of the form and track the build ID.
-    $form_state = array();
+    $form_state = new FormState();
     $form = $this->formBuilder->buildForm($form_arg, $form_state);
     $original_build_id = $form['#build_id'];
 
@@ -348,7 +351,7 @@ public function testGetCache() {
       ->will($this->returnValue(TRUE));
 
     // Do an initial build of the form and track the build ID.
-    $form_state = array();
+    $form_state = new FormState();
     $form_state['build_info']['args'] = array();
     $form_state['build_info']['files'] = array(array('module' => 'node', 'type' => 'pages.inc'));
     $form_state['cache'] = TRUE;
@@ -365,10 +368,11 @@ public function testGetCache() {
       ->will($this->returnValue($cached_form));
     $this->formStateCache->expects($this->once())
       ->method('get')
-      ->will($this->returnValue($form_state));
+      ->will($this->returnValue($form_state->getCacheableArray()));
 
     // The final form build will not trigger any actual form building, but will
     // use the form cache.
+    $form_state['executed'] = TRUE;
     $form_state['input']['form_id'] = $form_id;
     $form_state['input']['form_build_id'] = $form['#build_id'];
     $this->formBuilder->buildForm($form_arg, $form_state);
@@ -392,7 +396,7 @@ public function testSendResponse() {
     $form_arg = $this->getMockForm($form_id, $expected_form);
 
     // Do an initial build of the form and track the build ID.
-    $form_state = array();
+    $form_state = new FormState();
     $this->formBuilder->buildForm($form_arg, $form_state);
   }
 
@@ -413,11 +417,15 @@ public function testUniqueHtmlId() {
       ->method('buildForm')
       ->will($this->returnValue($expected_form));
 
-    $form_state = array();
+    $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
+      ->setMethods(array('drupalSetMessage'))
+      ->getMock();
     $form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
     $this->assertSame($form_id, $form['#id']);
 
-    $form_state = array();
+    $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
+      ->setMethods(array('drupalSetMessage'))
+      ->getMock();
     $form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
     $this->assertSame("$form_id--2", $form['#id']);
   }
@@ -429,11 +437,11 @@ public function getFormId() {
     return 'test_form';
   }
 
-  public function buildForm(array $form, array &$form_state) {
+  public function buildForm(array $form, FormStateInterface $form_state) {
     return test_form_id();
   }
-  public function validateForm(array &$form, array &$form_state) { }
-  public function submitForm(array &$form, array &$form_state) { }
+  public function validateForm(array &$form, FormStateInterface $form_state) { }
+  public function submitForm(array &$form, FormStateInterface $form_state) { }
 }
 class TestFormInjected extends TestForm implements ContainerInjectionInterface {
   public static function create(ContainerInterface $container) {
@@ -444,7 +452,9 @@ public static function create(ContainerInterface $container) {
 }
 
 namespace {
-  function test_form_id_custom_submit(array &$form, array &$form_state) {
+  use Drupal\Core\Form\FormStateInterface;
+
+  function test_form_id_custom_submit(array &$form, FormStateInterface $form_state) {
   }
   // @todo Remove once watchdog() is removed.
   if (!defined('WATCHDOG_ERROR')) {
diff --git a/core/tests/Drupal/Tests/Core/Form/FormStateTest.php b/core/tests/Drupal/Tests/Core/Form/FormStateTest.php
new file mode 100644
index 0000000..3c60ddf
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Form/FormStateTest.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Form\FormStateTest.
+ */
+
+namespace Drupal\Tests\Core\Form;
+
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Url;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Form\FormState
+ *
+ * @group Form
+ */
+class FormStateTest extends UnitTestCase {
+
+  /**
+   * Tests the getRedirect() method.
+   *
+   * @covers ::getRedirect
+   *
+   * @dataProvider providerTestGetRedirect
+   */
+  public function testGetRedirect($form_state_additions, $expected) {
+    $form_state = new FormState($form_state_additions);
+    $redirect = $form_state->getRedirect();
+    $this->assertEquals($expected, $redirect);
+  }
+
+  /**
+   * Provides test data for testing the getRedirect() method.
+   *
+   * @return array
+   *   Returns some test data.
+   */
+  public function providerTestGetRedirect() {
+    $data = array();
+    $data[] = array(array(), NULL);
+
+    $data[] = array(array('redirect' => 'foo'), 'foo');
+    $data[] = array(array('redirect' => array('foo')), array('foo'));
+    $data[] = array(array('redirect' => array('bar', array('query' => array('foo' => 'baz')))), array('bar', array('query' => array('foo' => 'baz'))));
+    $data[] = array(array('redirect' => array('baz', array(), 301)), array('baz', array(), 301));
+
+    $redirect = new RedirectResponse('/example');
+    $data[] = array(array('redirect' => $redirect), $redirect);
+
+    $data[] = array(array('redirect_route' => array('route_name' => 'test_route_a')), new Url('test_route_a', array(), array('absolute' => TRUE)));
+    $data[] = array(array('redirect_route' => array('route_name' => 'test_route_b', 'route_parameters' => array('key' => 'value'))), new Url('test_route_b', array('key' => 'value'), array('absolute' => TRUE)));
+    $data[] = array(array('redirect_route' => new Url('test_route_b', array('key' => 'value'))), new Url('test_route_b', array('key' => 'value'), array('absolute' => TRUE)));
+
+    $data[] = array(array('programmed' => TRUE), NULL);
+    $data[] = array(array('rebuild' => TRUE), NULL);
+    $data[] = array(array('no_redirect' => TRUE), NULL);
+    $data[] = array(array('redirect' => FALSE), NULL);
+
+    return $data;
+  }
+
+  /**
+   * Tests the setError() method.
+   *
+   * @covers ::setError
+   */
+  public function testSetError() {
+    $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
+      ->setMethods(array('drupalSetMessage'))
+      ->getMock();
+    $form_state->expects($this->once())
+      ->method('drupalSetMessage')
+      ->willReturn('Fail');
+
+    $element['#parents'] = array('foo', 'bar');
+    $form_state->setError($element, 'Fail');
+  }
+
+  /**
+   * Tests the getError() method.
+   *
+   * @covers ::getError
+   *
+   * @dataProvider providerTestGetError
+   */
+  public function testGetError($errors, $parents, $error = NULL) {
+    $element['#parents'] = $parents;
+    $form_state = new FormState(array(
+      'errors' => $errors,
+    ));
+    $this->assertSame($error, $form_state->getError($element));
+  }
+
+  public function providerTestGetError() {
+    return array(
+      array(array(), array('foo')),
+      array(array('foo][bar' => 'Fail'), array()),
+      array(array('foo][bar' => 'Fail'), array('foo')),
+      array(array('foo][bar' => 'Fail'), array('bar')),
+      array(array('foo][bar' => 'Fail'), array('baz')),
+      array(array('foo][bar' => 'Fail'), array('foo', 'bar'), 'Fail'),
+      array(array('foo][bar' => 'Fail'), array('foo', 'bar', 'baz'), 'Fail'),
+      array(array('foo][bar' => 'Fail 2'), array('foo')),
+      array(array('foo' => 'Fail 1', 'foo][bar' => 'Fail 2'), array('foo'), 'Fail 1'),
+      array(array('foo' => 'Fail 1', 'foo][bar' => 'Fail 2'), array('foo', 'bar'), 'Fail 1'),
+    );
+  }
+
+  /**
+   * @covers ::setErrorByName
+   *
+   * @dataProvider providerTestSetErrorByName
+   */
+  public function testSetErrorByName($limit_validation_errors, $expected_errors, $set_message = FALSE) {
+    $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
+      ->setConstructorArgs(array(array('limit_validation_errors' => $limit_validation_errors)))
+      ->setMethods(array('drupalSetMessage'))
+      ->getMock();
+    $form_state->clearErrors();
+    $form_state->expects($set_message ? $this->once() : $this->never())
+      ->method('drupalSetMessage');
+
+    $form_state->setErrorByName('test', 'Fail 1');
+    $form_state->setErrorByName('test', 'Fail 2');
+    $form_state->setErrorByName('options');
+
+    $this->assertSame(!empty($expected_errors), $form_state::hasAnyErrors());
+    $this->assertSame($expected_errors, $form_state['errors']);
+  }
+
+  public function providerTestSetErrorByName() {
+    return array(
+      // Only validate the 'options' element.
+      array(array(array('options')), array('options' => '')),
+      // Do not limit an validation, and, ensuring the first error is returned
+      // for the 'test' element.
+      array(NULL, array('test' => 'Fail 1', 'options' => ''), TRUE),
+      // Limit all validation.
+      array(array(), array()),
+    );
+  }
+
+  /**
+   * Tests that form errors during submission throw an exception.
+   *
+   * @covers ::setErrorByName
+   *
+   * @expectedException \LogicException
+   * @expectedExceptionMessage Form errors cannot be set after form validation has finished.
+   */
+  public function testFormErrorsDuringSubmission() {
+    $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
+      ->setConstructorArgs(array(array('validation_complete' => TRUE)))
+      ->setMethods(array('drupalSetMessage'))
+      ->getMock();
+    $form_state->setErrorByName('test', 'message');
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php b/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
index cc34f74..0bdc009 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Core\Form;
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Form\FormState;
 use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -41,7 +42,7 @@ public function setUp() {
   public function testHandleFormSubmissionNotSubmitted() {
     $form_submitter = $this->getFormSubmitter();
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
 
     $return = $form_submitter->doSubmitForm($form, $form_state);
     $this->assertFalse($form_state['executed']);
@@ -54,9 +55,10 @@ public function testHandleFormSubmissionNotSubmitted() {
   public function testHandleFormSubmissionNoRedirect() {
     $form_submitter = $this->getFormSubmitter();
     $form = array();
-    $form_state = $this->getFormStateDefaults();
-    $form_state['submitted'] = TRUE;
-    $form_state['no_redirect'] = TRUE;
+    $form_state = new FormState(array(
+      'submitted' => TRUE,
+      'no_redirect' => TRUE,
+    ));
 
     $return = $form_submitter->doSubmitForm($form, $form_state);
     $this->assertTrue($form_state['executed']);
@@ -76,9 +78,10 @@ public function testHandleFormSubmissionWithResponses($class, $form_state_key) {
       ->method('prepare')
       ->will($this->returnValue($response));
 
-    $form_state = $this->getFormStateDefaults();
-    $form_state['submitted'] = TRUE;
-    $form_state[$form_state_key] = $response;
+    $form_state = new FormState(array(
+      'submitted' => TRUE,
+      $form_state_key => $response,
+    ));
 
     $form_submitter = $this->getFormSubmitter();
     $form = array();
@@ -101,7 +104,7 @@ public function providerTestHandleFormSubmissionWithResponses() {
    *
    * @dataProvider providerTestRedirectWithResult
    */
-  public function testRedirectWithResult($form_state, $result, $status = 303) {
+  public function testRedirectWithResult($redirect_value, $result, $status = 303) {
     $form_submitter = $this->getFormSubmitter();
     $this->urlGenerator->expects($this->once())
       ->method('generateFromPath')
@@ -113,20 +116,39 @@ public function testRedirectWithResult($form_state, $result, $status = 303) {
         ))
       );
 
-    $form_state += $this->getFormStateDefaults();
+    $form_state = $this->getMock('Drupal\Core\Form\FormStateInterface');
+    $form_state->expects($this->once())
+      ->method('getRedirect')
+      ->willReturn($redirect_value);
     $redirect = $form_submitter->redirectForm($form_state);
     $this->assertSame($result, $redirect->getTargetUrl());
     $this->assertSame($status, $redirect->getStatusCode());
   }
 
   /**
+   * Provides test data for testing the redirectForm() method with a redirect.
+   *
+   * @return array
+   *   Returns some test data.
+   */
+  public function providerTestRedirectWithResult() {
+    return array(
+      array(NULL, '<front>'),
+      array('foo', 'foo'),
+      array(array('foo'), 'foo'),
+      array(array('bar', array('query' => array('foo' => 'baz'))), 'bar'),
+      array(array('baz', array(), 301), 'baz', 301),
+    );
+  }
+
+  /**
    * Tests the redirectForm() with redirect_route when a redirect is expected.
    *
    * @covers ::redirectForm
    *
    * @dataProvider providerTestRedirectWithRouteWithResult
    */
-  public function testRedirectWithRouteWithResult($form_state, $result, $status = 303) {
+  public function testRedirectWithRouteWithResult($redirect_value, $result, $status = 303) {
     $container = new ContainerBuilder();
     $container->set('url_generator', $this->urlGenerator);
     \Drupal::setContainer($container);
@@ -139,13 +161,29 @@ public function testRedirectWithRouteWithResult($form_state, $result, $status =
         ))
       );
 
-    $form_state += $this->getFormStateDefaults();
+    $form_state = $this->getMock('Drupal\Core\Form\FormStateInterface');
+    $form_state->expects($this->once())
+      ->method('getRedirect')
+      ->willReturn($redirect_value);
     $redirect = $form_submitter->redirectForm($form_state);
     $this->assertSame($result, $redirect->getTargetUrl());
     $this->assertSame($status, $redirect->getStatusCode());
   }
 
   /**
+   * Provides test data for testing the redirectForm() method with a route name.
+   *
+   * @return array
+   *   Returns some test data.
+   */
+  public function providerTestRedirectWithRouteWithResult() {
+    return array(
+      array(new Url('test_route_a', array(), array('absolute' => TRUE)), 'test-route'),
+      array(new Url('test_route_b', array('key' => 'value'), array('absolute' => TRUE)), 'test-route/value'),
+    );
+  }
+
+  /**
    * Tests the redirectForm() method with a response object.
    *
    * @covers ::redirectForm
@@ -153,9 +191,11 @@ public function testRedirectWithRouteWithResult($form_state, $result, $status =
   public function testRedirectWithResponseObject() {
     $form_submitter = $this->getFormSubmitter();
     $redirect = new RedirectResponse('/example');
-    $form_state['redirect'] = $redirect;
+    $form_state = $this->getMock('Drupal\Core\Form\FormStateInterface');
+    $form_state->expects($this->once())
+      ->method('getRedirect')
+      ->willReturn($redirect);
 
-    $form_state += $this->getFormStateDefaults();
     $result_redirect = $form_submitter->redirectForm($form_state);
 
     $this->assertSame($redirect, $result_redirect);
@@ -165,67 +205,22 @@ public function testRedirectWithResponseObject() {
    * Tests the redirectForm() method when no redirect is expected.
    *
    * @covers ::redirectForm
-   *
-   * @dataProvider providerTestRedirectWithoutResult
    */
-  public function testRedirectWithoutResult($form_state) {
+  public function testRedirectWithoutResult() {
     $form_submitter = $this->getFormSubmitter();
     $this->urlGenerator->expects($this->never())
       ->method('generateFromPath');
     $this->urlGenerator->expects($this->never())
       ->method('generateFromRoute');
-    $form_state += $this->getFormStateDefaults();
+    $form_state = $this->getMock('Drupal\Core\Form\FormStateInterface');
+    $form_state->expects($this->once())
+      ->method('getRedirect')
+      ->willReturn(FALSE);
     $redirect = $form_submitter->redirectForm($form_state);
     $this->assertNull($redirect);
   }
 
   /**
-   * Provides test data for testing the redirectForm() method with a redirect.
-   *
-   * @return array
-   *   Returns some test data.
-   */
-  public function providerTestRedirectWithResult() {
-    return array(
-      array(array(), '<front>'),
-      array(array('redirect' => 'foo'), 'foo'),
-      array(array('redirect' => array('foo')), 'foo'),
-      array(array('redirect' => array('foo')), 'foo'),
-      array(array('redirect' => array('bar', array('query' => array('foo' => 'baz')))), 'bar'),
-      array(array('redirect' => array('baz', array(), 301)), 'baz', 301),
-    );
-  }
-
-  /**
-   * Provides test data for testing the redirectForm() method with a route name.
-   *
-   * @return array
-   *   Returns some test data.
-   */
-  public function providerTestRedirectWithRouteWithResult() {
-    return array(
-      array(array('redirect_route' => array('route_name' => 'test_route_a')), 'test-route'),
-      array(array('redirect_route' => array('route_name' => 'test_route_b', 'route_parameters' => array('key' => 'value'))), 'test-route/value'),
-      array(array('redirect_route' => new Url('test_route_b', array('key' => 'value'))), 'test-route/value'),
-    );
-  }
-
-  /**
-   * Provides test data for testing the redirectForm() method with no redirect.
-   *
-   * @return array
-   *   Returns some test data.
-   */
-  public function providerTestRedirectWithoutResult() {
-    return array(
-      array(array('programmed' => TRUE)),
-      array(array('rebuild' => TRUE)),
-      array(array('no_redirect' => TRUE)),
-      array(array('redirect' => FALSE)),
-    );
-  }
-
-  /**
    * @covers ::executeSubmitHandlers
    */
   public function testExecuteSubmitHandlers() {
@@ -233,13 +228,13 @@ public function testExecuteSubmitHandlers() {
     $mock = $this->getMock('stdClass', array('submit_handler', 'hash_submit'));
     $mock->expects($this->once())
       ->method('submit_handler')
-      ->with($this->isType('array'), $this->isType('array'));
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
     $mock->expects($this->once())
       ->method('hash_submit')
-      ->with($this->isType('array'), $this->isType('array'));
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
 
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_submitter->executeSubmitHandlers($form, $form_state);
 
     $form['#submit'][] = array($mock, 'hash_submit');
@@ -251,17 +246,6 @@ public function testExecuteSubmitHandlers() {
   }
 
   /**
-   * @return array()
-   */
-  protected function getFormStateDefaults() {
-    $form_builder = $this->getMockBuilder('Drupal\Core\Form\FormBuilder')
-      ->disableOriginalConstructor()
-      ->setMethods(NULL)
-      ->getMock();
-    return $form_builder->getFormStateDefaults();
-  }
-
-  /**
    * @return \Drupal\Core\Form\FormSubmitterInterface
    */
   protected function getFormSubmitter() {
diff --git a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php
index 9bb00d2..08eaa31 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\FormBuilder;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
@@ -221,8 +222,8 @@ protected function getMockForm($form_id, $expected_form = NULL, $count = 1) {
    *   The unique string identifying the form.
    * @param \Drupal\Core\Form\FormInterface $form_arg
    *   The form object.
-   * @param array $form_state
-   *   An associative array containing the current state of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    * @param bool $programmed
    *   Whether $form_state['programmed'] should be set to TRUE or not. If it is
    *   not set to TRUE, you must provide additional data in $form_state for the
@@ -231,7 +232,7 @@ protected function getMockForm($form_id, $expected_form = NULL, $count = 1) {
    * @return array
    *   The built form.
    */
-  protected function simulateFormSubmission($form_id, FormInterface $form_arg, array &$form_state, $programmed = TRUE) {
+  protected function simulateFormSubmission($form_id, FormInterface $form_arg, FormStateInterface $form_state, $programmed = TRUE) {
     $form_state['build_info']['callback_object'] = $form_arg;
     $form_state['build_info']['args'] = array();
     $form_state['input']['op'] = 'Submit';
diff --git a/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php b/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
index 0870788..a0e9f47 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Core\Form {
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormState;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -19,23 +20,6 @@
 class FormValidatorTest extends UnitTestCase {
 
   /**
-   * Tests that form errors during submission throw an exception.
-   *
-   * @covers ::setErrorByName
-   *
-   * @expectedException \LogicException
-   * @expectedExceptionMessage Form errors cannot be set after form validation has finished.
-   */
-  public function testFormErrorsDuringSubmission() {
-    $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
-      ->disableOriginalConstructor()
-      ->setMethods(NULL)
-      ->getMock();
-    $form_state['validation_complete'] = TRUE;
-    $form_validator->setErrorByName('test', $form_state, 'message');
-  }
-
-  /**
    * Tests the 'validation_complete' $form_state flag.
    *
    * @covers ::validateForm
@@ -48,7 +32,7 @@ public function testValidationComplete() {
       ->getMock();
 
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $this->assertFalse($form_state['validation_complete']);
     $form_validator->validateForm('test_form_id', $form, $form_state);
     $this->assertTrue($form_state['validation_complete']);
@@ -68,7 +52,7 @@ public function testPreventDuplicateValidation() {
       ->method('doValidateForm');
 
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_state['validation_complete'] = TRUE;
     $form_validator->validateForm('test_form_id', $form, $form_state);
     $this->assertArrayNotHasKey('#errors', $form);
@@ -88,7 +72,7 @@ public function testMustValidate() {
       ->method('doValidateForm');
 
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_state['validation_complete'] = TRUE;
     $form_state['must_validate'] = TRUE;
     $form_validator->validateForm('test_form_id', $form, $form_state);
@@ -115,12 +99,12 @@ public function testValidateInvalidFormToken() {
       ->getMock();
     $form_validator->expects($this->once())
       ->method('setErrorByName')
-      ->with('form_token', $this->isType('array'), 'The form has become outdated. Copy any unsaved work in the form below and then <a href="/test/example?foo=bar">reload this page</a>.');
+      ->with('form_token', $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'), 'The form has become outdated. Copy any unsaved work in the form below and then <a href="/test/example?foo=bar">reload this page</a>.');
     $form_validator->expects($this->never())
       ->method('doValidateForm');
 
     $form['#token'] = 'test_form_id';
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_state['values']['form_token'] = 'some_random_token';
     $form_validator->validateForm('test_form_id', $form, $form_state);
     $this->assertTrue($form_state['validation_complete']);
@@ -148,120 +132,19 @@ public function testValidateValidFormToken() {
       ->method('doValidateForm');
 
     $form['#token'] = 'test_form_id';
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_state['values']['form_token'] = 'some_random_token';
     $form_validator->validateForm('test_form_id', $form, $form_state);
     $this->assertTrue($form_state['validation_complete']);
   }
 
   /**
-   * Tests the setError() method.
-   *
-   * @covers ::setError
-   */
-  public function testSetError() {
-    $form_state = $this->getFormStateDefaults();
-
-    $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
-      ->disableOriginalConstructor()
-      ->setMethods(array('setErrorByName'))
-      ->getMock();
-    $form_validator->expects($this->once())
-      ->method('setErrorByName')
-      ->with('foo][bar', $form_state, 'Fail');
-
-    $element['#parents'] = array('foo', 'bar');
-    $form_validator->setError($element, $form_state, 'Fail');
-  }
-
-  /**
-   * Tests the getError() method.
-   *
-   * @covers ::getError
-   *
-   * @dataProvider providerTestGetError
-   */
-  public function testGetError($errors, $parents, $error = NULL) {
-    $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
-      ->disableOriginalConstructor()
-      ->setMethods(NULL)
-      ->getMock();
-
-    $element['#parents'] = $parents;
-    $form_state = $this->getFormStateDefaults();
-    $form_state['errors'] = $errors;
-    $this->assertSame($error, $form_validator->getError($element, $form_state));
-  }
-
-  public function providerTestGetError() {
-    return array(
-      array(array(), array('foo')),
-      array(array('foo][bar' => 'Fail'), array()),
-      array(array('foo][bar' => 'Fail'), array('foo')),
-      array(array('foo][bar' => 'Fail'), array('bar')),
-      array(array('foo][bar' => 'Fail'), array('baz')),
-      array(array('foo][bar' => 'Fail'), array('foo', 'bar'), 'Fail'),
-      array(array('foo][bar' => 'Fail'), array('foo', 'bar', 'baz'), 'Fail'),
-      array(array('foo][bar' => 'Fail 2'), array('foo')),
-      array(array('foo' => 'Fail 1', 'foo][bar' => 'Fail 2'), array('foo'), 'Fail 1'),
-      array(array('foo' => 'Fail 1', 'foo][bar' => 'Fail 2'), array('foo', 'bar'), 'Fail 1'),
-    );
-  }
-
-  /**
-   * @covers ::setErrorByName
-   *
-   * @dataProvider providerTestSetErrorByName
-   */
-  public function testSetErrorByName($limit_validation_errors, $expected_errors, $set_message = FALSE) {
-    $request_stack = new RequestStack();
-    $request = new Request();
-    $request_stack->push($request);
-    $csrf_token = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
-      ->setConstructorArgs(array($request_stack, $this->getStringTranslationStub(), $csrf_token))
-      ->setMethods(array('drupalSetMessage'))
-      ->getMock();
-    $form_validator->expects($set_message ? $this->once() : $this->never())
-      ->method('drupalSetMessage');
-
-    $form_state = $this->getFormStateDefaults();
-    $form_state['limit_validation_errors'] = $limit_validation_errors;
-    $form_validator->setErrorByName('test', $form_state, 'Fail 1');
-    $form_validator->setErrorByName('test', $form_state, 'Fail 2');
-    $form_validator->setErrorByName('options', $form_state);
-
-    $this->assertSame(!empty($expected_errors), $request->attributes->get('_form_errors', FALSE));
-    $this->assertSame($expected_errors, $form_state['errors']);
-  }
-
-  public function providerTestSetErrorByName() {
-    return array(
-      // Only validate the 'options' element.
-      array(array(array('options')), array('options' => '')),
-      // Do not limit an validation, and, ensuring the first error is returned
-      // for the 'test' element.
-      array(NULL, array('test' => 'Fail 1', 'options' => ''), TRUE),
-      // Limit all validation.
-      array(array(), array()),
-    );
-  }
-
-  /**
    * @covers ::setElementErrorsFromFormState
    */
   public function testSetElementErrorsFromFormState() {
-    $request_stack = new RequestStack();
-    $request = new Request();
-    $request_stack->push($request);
-    $csrf_token = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator')
-      ->disableOriginalConstructor()
-      ->getMock();
     $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
-      ->setConstructorArgs(array($request_stack, $this->getStringTranslationStub(), $csrf_token))
-      ->setMethods(array('drupalSetMessage'))
+      ->disableOriginalConstructor()
+      ->setMethods(NULL)
       ->getMock();
 
     $form = array(
@@ -272,7 +155,9 @@ public function testSetElementErrorsFromFormState() {
       '#title' => 'Test',
       '#parents' => array('test'),
     );
-    $form_state = $this->getFormStateDefaults();
+    $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
+      ->setMethods(array('drupalSetMessage'))
+      ->getMock();
     $form_validator->setErrorByName('test', $form_state, 'invalid');
     $form_validator->validateForm('test_form_id', $form, $form_state);
     $this->assertSame('invalid', $form['test']['#errors']);
@@ -290,7 +175,7 @@ public function testHandleErrorsWithLimitedValidation($sections, $triggering_ele
       ->getMock();
 
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_state['triggering_element'] = $triggering_element;
     $form_state['triggering_element']['#limit_validation_errors'] = $sections;
 
@@ -387,13 +272,13 @@ public function testExecuteValidateHandlers() {
     $mock = $this->getMock('stdClass', array('validate_handler', 'hash_validate'));
     $mock->expects($this->once())
       ->method('validate_handler')
-      ->with($this->isType('array'), $this->isType('array'));
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
     $mock->expects($this->once())
       ->method('hash_validate')
-      ->with($this->isType('array'), $this->isType('array'));
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
 
     $form = array();
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_validator->executeValidateHandlers($form, $form_state);
 
     $form['#validate'][] = array($mock, 'hash_validate');
@@ -415,13 +300,13 @@ public function testRequiredErrorMessage($element, $expected_message) {
       ->getMock();
     $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
       ->setConstructorArgs(array(new RequestStack(), $this->getStringTranslationStub(), $csrf_token))
-      ->setMethods(array('executeValidateHandlers', 'setErrorByName'))
+      ->setMethods(array('executeValidateHandlers', 'setError'))
       ->getMock();
     $form_validator->expects($this->once())
       ->method('executeValidateHandlers');
     $form_validator->expects($this->once())
-      ->method('setErrorByName')
-      ->with('test', $this->isType('array'), $expected_message);
+      ->method('setError')
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'), $expected_message);
 
     $form = array();
     $form['test'] = $element + array(
@@ -431,7 +316,7 @@ public function testRequiredErrorMessage($element, $expected_message) {
       '#required' => TRUE,
       '#parents' => array('test'),
     );
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_validator->validateForm('test_form_id', $form, $form_state);
   }
 
@@ -468,7 +353,7 @@ public function testElementValidate() {
     $mock = $this->getMock('stdClass', array('element_validate'));
     $mock->expects($this->once())
       ->method('element_validate')
-      ->with($this->isType('array'), $this->isType('array'), NULL);
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'), NULL);
 
     $form = array();
     $form['test'] = array(
@@ -477,7 +362,7 @@ public function testElementValidate() {
       '#parents' => array('test'),
       '#element_validate' => array(array($mock, 'element_validate')),
     );
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_validator->validateForm('test_form_id', $form, $form_state);
   }
 
@@ -492,11 +377,11 @@ public function testPerformRequiredValidation($element, $expected_message, $call
       ->getMock();
     $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
       ->setConstructorArgs(array(new RequestStack(), $this->getStringTranslationStub(), $csrf_token))
-      ->setMethods(array('setErrorByName', 'watchdog'))
+      ->setMethods(array('setError', 'watchdog'))
       ->getMock();
     $form_validator->expects($this->once())
-      ->method('setErrorByName')
-      ->with('test', $this->isType('array'), $expected_message);
+      ->method('setError')
+      ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'), $expected_message);
 
     if ($call_watchdog) {
       $form_validator->expects($this->once())
@@ -511,7 +396,7 @@ public function testPerformRequiredValidation($element, $expected_message, $call
       '#required' => FALSE,
       '#parents' => array('test'),
     );
-    $form_state = $this->getFormStateDefaults();
+    $form_state = new FormState();
     $form_state['values'] = array();
     $form_validator->validateForm('test_form_id', $form, $form_state);
   }
@@ -584,17 +469,6 @@ public function providerTestPerformRequiredValidation() {
     );
   }
 
-  /**
-   * @return array()
-   */
-  protected function getFormStateDefaults() {
-    $form_builder = $this->getMockBuilder('Drupal\Core\Form\FormBuilder')
-      ->disableOriginalConstructor()
-      ->setMethods(NULL)
-      ->getMock();
-    return $form_builder->getFormStateDefaults();
-  }
-
 }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/Menu/MenuLinkMock.php b/core/tests/Drupal/Tests/Core/Menu/MenuLinkMock.php
index 7086aa6..9a9e98e 100644
--- a/core/tests/Drupal/Tests/Core/Menu/MenuLinkMock.php
+++ b/core/tests/Drupal/Tests/Core/Menu/MenuLinkMock.php
@@ -28,7 +28,6 @@ class MenuLinkMock extends MenuLinkBase {
     'options' => array(),
     'expanded' => '0',
     'hidden' => '0',
-    'discovered' => '1',
     'provider' => 'simpletest',
     'metadata' => array(),
     'class' => 'Drupal\\Tests\\Core\Menu\\MenuLinkMock',
diff --git a/core/themes/bartik/bartik.theme b/core/themes/bartik/bartik.theme
index 836a8f7..27f8973 100644
--- a/core/themes/bartik/bartik.theme
+++ b/core/themes/bartik/bartik.theme
@@ -55,18 +55,15 @@ function bartik_preprocess_page(&$variables) {
   // Store back the classes to the htmlpage object.
   $attributes['class'] = $classes;
 
-  // Pass the main menu and secondary menu to the template as render arrays.
+  // Set additional attributes on the primary and secondary navigation menus.
   if (!empty($variables['main_menu'])) {
     $variables['main_menu']['#attributes']['id'] = 'main-menu-links';
-    $variables['main_menu']['#attributes']['class'] = array('links', 'clearfix');
+    $variables['main_menu']['#attributes']['class'][] = 'links';
   }
   if (!empty($variables['secondary_menu'])) {
     $variables['secondary_menu']['#attributes']['id'] = 'secondary-menu-links';
-    $variables['secondary_menu']['#attributes']['class'] = array(
-      'links',
-      'inline',
-      'clearfix',
-    );
+    $variables['secondary_menu']['#attributes']['class'][] = 'links';
+    $variables['secondary_menu']['#attributes']['class'][] = 'inline';
   }
 
   // Set the options that apply to both page and maintenance page.
@@ -138,10 +135,12 @@ function bartik_preprocess_block(&$variables) {
 }
 
 /**
- * Implements THEME_menu_tree().
+ * Implements hook_preprocess_HOOK() for menu-tree.html.twig.
+ *
+ * @see template_preprocess_menu_tree()
  */
-function bartik_menu_tree($variables) {
-  return '<ul class="menu clearfix">' . $variables['tree'] . '</ul>';
+function bartik_preprocess_menu_tree(&$variables) {
+  $variables['attributes']['class'][] = 'clearfix';
 }
 
 /**
diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme
index 8cdc9c1..18652ad 100644
--- a/core/themes/seven/seven.theme
+++ b/core/themes/seven/seven.theme
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\Xss;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Implements hook_preprocess_HOOK() for page templates.
@@ -145,7 +146,7 @@ function seven_preprocess_block_content_add_list(&$variables) {
 function seven_preprocess_admin_block_content(&$variables) {
   if (!empty($variables['content'])) {
     foreach ($variables['content'] as $key => $item) {
-      $variables['content'][$key]['url'] = url($item['link_path']);
+      $variables['content'][$key]['url'] = $item['url']->toString();
     }
   }
 }
@@ -265,9 +266,9 @@ function seven_preprocess_maintenance_page(&$variables) {
  *
  * Changes vertical tabs to container and adds meta information.
  */
-function seven_form_node_form_alter(&$form, &$form_state) {
+function seven_form_node_form_alter(&$form, FormStateInterface $form_state) {
   /** @var \Drupal\node\NodeInterface $node */
-  $node = $form_state['controller']->getEntity();
+  $node = $form_state->get('controller')->getEntity();
 
   $form['#theme'] = array('node_edit_form');
   $form['#attached']['css'][] = drupal_get_path('module', 'node') . '/css/node.module.css';
