diff --git a/core/includes/form.inc b/core/includes/form.inc
index 2f9dc7f..156f3ee 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -148,11 +148,7 @@ function _drupal_form_id($form_arg, &$form_state) {
  * @param \Drupal\Core\Form\FormInterface|string $form_arg
  *   A form object to use to build the form, or the unique string identifying
  *   the desired form. If $form_arg is a string and a function with that
- *   name exists, it is called to build the form array. Modules that need to
- *   generate the same form (or very similar forms) using different $form_ids
- *   can implement hook_forms(), which maps different $form_id values to the
- *   proper form constructor function. Examples may be found in node_forms(),
- *   and search_forms().
+ *   name exists, it is called to build the form array.
  * @param ...
  *   Any additional arguments are passed on to the functions called by
  *   drupal_get_form(), including the unique form constructor function. For
@@ -187,11 +183,7 @@ function drupal_get_form($form_arg) {
  *
  * @param $form_id
  *   The unique string identifying the desired form. If a function with that
- *   name exists, it is called to build the form array. Modules that need to
- *   generate the same form (or very similar forms) using different $form_ids
- *   can implement hook_forms(), which maps different $form_id values to the
- *   proper form constructor function. Examples may be found in node_forms(),
- *   and search_forms().
+ *   name exists, it is called to build the form array.
  * @param $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
@@ -215,8 +207,8 @@ function drupal_get_form($form_arg) {
  *       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 a
- *       hook_forms() implementation.
+ *     - 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
  *     drupal_rebuild_form().
  *   - rebuild: Normally, after the entire form processing is completed and
@@ -330,14 +322,6 @@ function drupal_get_form($form_arg) {
  *     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.
- *   - wrapper_callback: Modules that wish to pre-populate certain forms with
- *     common elements, such as back/next/save buttons in multi-step form
- *     wizards, may define a form builder function name that returns a form
- *     structure, which is passed on to the actual form builder function.
- *     Such implementations may either define the 'wrapper_callback' via
- *     hook_forms() or have to invoke drupal_build_form() (instead of
- *     drupal_get_form()) on their own in a custom menu callback to prepare
- *     $form_state accordingly.
  *   Information on how certain $form_state properties control redirection
  *   behavior after form submission may be found in drupal_redirect_form().
  *
@@ -481,10 +465,6 @@ function form_state_defaults() {
  * @param $form_id
  *   The unique string identifying the desired form. If a function
  *   with that name exists, it is called to build the form array.
- *   Modules that need to generate the same form (or very similar forms)
- *   using different $form_ids can implement hook_forms(), which maps
- *   different $form_id values to the proper form constructor function. Examples
- *   may be found in node_forms() and search_forms().
  * @param $form_state
  *   A keyed array containing the current state of the form.
  * @param $old_form
@@ -684,11 +664,7 @@ function form_load_include(&$form_state, $type, $module, $name = NULL) {
  * @param \Drupal\Core\Form\FormInterface|string $form_arg
  *   A form object to use to build the form, or the unique string identifying
  *   the desired form. If $form_arg is a string and a function with that
- *   name exists, it is called to build the form array. Modules that need to
- *   generate the same form (or very similar forms) using different $form_ids
- *   can implement hook_forms(), which maps different $form_id values to the
- *   proper form constructor function. Examples may be found in node_forms()
- *   and search_forms().
+ *   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
@@ -764,9 +740,6 @@ function drupal_form_submit($form_arg, &$form_state) {
  * @param $form_id
  *   The unique string identifying the desired form. If a function
  *   with that name exists, it is called to build the form array.
- *   Modules that need to generate the same form (or very similar forms)
- *   using different $form_ids can implement hook_forms(), which maps
- *   different $form_id values to the proper form constructor function.
  * @param $form_state
  *   A keyed array containing the current state of the form, including the
  *   additional arguments to drupal_get_form() or drupal_form_submit() in the
@@ -808,38 +781,6 @@ function drupal_retrieve_form($form_id, &$form_state) {
     $callback = array($form_state['build_info']['callback_object'], 'buildForm');
   }
 
-  // We first check to see if there is a valid form builder callback defined.
-  // If there is, we simply pass the arguments on to it to get the form.
-  if (!is_callable($callback)) {
-    // In cases where many form_ids need to share a central constructor function,
-    // such as the node editing form, modules can implement hook_forms(). It
-    // maps one or more form_ids to the correct constructor functions.
-    //
-    // We cache the results of that hook to save time, but that only works
-    // for modules that know all their form_ids in advance. (A module that
-    // adds a small 'rate this comment' form to each comment in a list
-    // would need a unique form_id for each one, for example.)
-    //
-    // So, we call the hook if $forms isn't yet populated, OR if it doesn't
-    // yet have an entry for the requested form_id.
-    if (!isset($forms) || !isset($forms[$form_id])) {
-      $forms = \Drupal::moduleHandler()->invokeAll('forms', array($form_id, $args));
-    }
-    $form_definition = $forms[$form_id];
-    if (isset($form_definition['callback arguments'])) {
-      $args = array_merge($form_definition['callback arguments'], $args);
-    }
-    if (isset($form_definition['callback'])) {
-      $callback = $form_definition['callback'];
-      $form_state['build_info']['base_form_id'] = $callback;
-    }
-    // In case $form_state['wrapper_callback'] is not defined already, we also
-    // allow hook_forms() to define one.
-    if (!isset($form_state['wrapper_callback']) && isset($form_definition['wrapper_callback'])) {
-      $form_state['wrapper_callback'] = $form_definition['wrapper_callback'];
-    }
-  }
-
   $form = array();
   // Assign a default CSS class name based on $form_id.
   // This happens here and not in drupal_prepare_form() in order to allow the
@@ -855,20 +796,6 @@ function drupal_retrieve_form($form_id, &$form_state) {
   // explicitly.
   $args = array_merge(array($form, &$form_state), $args);
 
-  // When the passed $form_state (not using drupal_get_form()) defines a
-  // 'wrapper_callback', then it requests to invoke a separate (wrapping) form
-  // builder function to pre-populate the $form array with form elements, which
-  // the actual form builder function ($callback) expects. This allows for
-  // pre-populating a form with common elements for certain forms, such as
-  // back/next/save buttons in multi-step form wizards. See drupal_build_form().
-  if (isset($form_state['wrapper_callback'])) {
-    $form = call_user_func_array($form_state['wrapper_callback'], $args);
-    // Put the prepopulated $form into $args.
-    $args[0] = $form;
-  }
-
-  // If $callback was returned by a hook_forms() implementation, call it.
-  // Otherwise, call the function named after the form id.
   $form = call_user_func_array($callback, $args);
   // If the form returns some kind of response, deliver it.
   if ($form instanceof Response) {
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index abda14e..2eb21cf 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -1001,9 +1001,6 @@ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * one exists) check the $form_state. The base form ID is stored under
  * $form_state['build_info']['base_form_id'].
  *
- * See hook_forms() for more information on how to implement base forms in
- * Drupal.
- *
  * Form alter hooks are called in the following order: hook_form_alter(),
  * hook_form_BASE_FORM_ID_alter(), hook_form_FORM_ID_alter(). See
  * hook_form_alter() for more details.
@@ -1019,7 +1016,6 @@ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * @see hook_form_alter()
  * @see hook_form_FORM_ID_alter()
  * @see drupal_prepare_form()
- * @see hook_forms()
  */
 function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
   // Modification for the form with the given BASE_FORM_ID goes here. For
@@ -1035,85 +1031,6 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
- * Map form_ids to form builder functions.
- *
- * By default, when drupal_get_form() is called, the system will look for a
- * function with the same name as the form ID, and use that function to build
- * the form. If no such function is found, Drupal calls this hook. Modules
- * implementing this hook can then provide their own instructions for mapping
- * form IDs to constructor functions. As a result, you can easily map multiple
- * form IDs to a single form constructor (referred to as a 'base' form).
- *
- * Using a base form can help to avoid code duplication, by allowing many
- * similar forms to use the same code base. Another benefit is that it becomes
- * much easier for other modules to apply a general change to the group of
- * forms; hook_form_BASE_FORM_ID_alter() can be used to easily alter multiple
- * forms at once by directly targeting the shared base form.
- *
- * Two example use cases where base forms may be useful are given below.
- *
- * First, you can use this hook to tell the form system to use a different
- * function to build certain forms in your module; this is often used to define
- * a form "factory" function that is used to build several similar forms. In
- * this case, your hook implementation will likely ignore all of the input
- * arguments. See node_forms() for an example of this. Note, node_forms() is the
- * hook_forms() implementation; the base form itself is defined in node_form().
- *
- * Second, you could use this hook to define how to build a form with a
- * dynamically-generated form ID. In this case, you would need to verify that
- * the $form_id input matched your module's format for dynamically-generated
- * form IDs, and if so, act appropriately.
- *
- * @param $form_id
- *   The unique string identifying the desired form.
- * @param $args
- *   An array containing the original arguments provided to drupal_get_form()
- *   or drupal_form_submit(). These are always passed to the form builder and
- *   do not have to be specified manually in 'callback arguments'.
- *
- * @return
- *   An associative array whose keys define form_ids and whose values are an
- *   associative array defining the following keys:
- *   - callback: The name of the form builder function to invoke. This will be
- *     used for the base form ID, for example, to target a base form using
- *     hook_form_BASE_FORM_ID_alter().
- *   - callback arguments: (optional) Additional arguments to pass to the
- *     function defined in 'callback', which are prepended to $args.
- *   - wrapper_callback: (optional) The name of a form builder function to
- *     invoke before the form builder defined in 'callback' is invoked. This
- *     wrapper callback may prepopulate the $form array with form elements,
- *     which will then be already contained in the $form that is passed on to
- *     the form builder defined in 'callback'. For example, a wrapper callback
- *     could setup wizard-alike form buttons that are the same for a variety of
- *     forms that belong to the wizard, which all share the same wrapper
- *     callback.
- */
-function hook_forms($form_id, $args) {
-  // Simply reroute the (non-existing) $form_id 'mymodule_first_form' to
-  // 'mymodule_main_form'.
-  $forms['mymodule_first_form'] = array(
-    'callback' => 'mymodule_main_form',
-  );
-
-  // Reroute the $form_id and prepend an additional argument that gets passed to
-  // the 'mymodule_main_form' form builder function.
-  $forms['mymodule_second_form'] = array(
-    'callback' => 'mymodule_main_form',
-    'callback arguments' => array('some parameter'),
-  );
-
-  // Reroute the $form_id, but invoke the form builder function
-  // 'mymodule_main_form_wrapper' first, so we can prepopulate the $form array
-  // that is passed to the actual form builder 'mymodule_main_form'.
-  $forms['mymodule_wrapped_form'] = array(
-    'callback' => 'mymodule_main_form',
-    'wrapper_callback' => 'mymodule_main_form_wrapper',
-  );
-
-  return $forms;
-}
-
-/**
  * Alter an email message created with the drupal_mail() function.
  *
  * hook_mail_alter() allows modification of email messages created and sent
