diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index fd712f7..31f2f6c 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1686,7 +1686,9 @@ function comment_form($form, &$form_state, Comment $comment) {
   }
 
   $node = node_load($comment->nid);
+  // @todo Remove all the usages of $form['#node'].
   $form['#node'] = $node;
+  $form_state['node'] = $node;
 
   // Use #comment-form as unique jump target, regardless of node type.
   $form['#id'] = drupal_html_id('comment_form');
@@ -1846,21 +1848,6 @@ function comment_form($form, &$form_state, Comment $comment) {
     '#value' => $comment_langcode,
   );
 
-  // Only show the save button if comment previews are optional or if we are
-  // already previewing the submission.
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    '#access' => ($comment->cid && user_access('administer comments')) || variable_get('comment_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_REQUIRED || isset($form_state['comment_preview']),
-  );
-  $form['actions']['preview'] = array(
-    '#type' => 'submit',
-    '#value' => t('Preview'),
-    '#access' => (variable_get('comment_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_DISABLED),
-    '#submit' => array('comment_form_build_preview'),
-  );
-
   // Attach fields.
   $comment->node_type = 'comment_node_' . $node->type;
 
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index b6d1692..6f61634 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -24,6 +24,33 @@ class CommentFormController extends EntityFormController {
   }
 
   /**
+   * @see Drupal\entity\EntityFormController::actions()
+   */
+  protected function actions(array $form, array &$form_state, EntityInterface $comment) {
+    $element = parent::actions($form, $form_state, $comment);
+    $node = $form_state['node'];
+    $preview_mode = variable_get('comment_preview_' . $node->type, DRUPAL_OPTIONAL);
+
+    // No delete action on the comment form.
+    unset($element['delete']);
+
+    // Only show the save button if comment previews are optional or if we are
+    // already previewing the submission.
+    $element['submit']['#access'] = ($comment->cid && user_access('administer comments')) || $preview_mode != DRUPAL_REQUIRED || isset($form_state['comment_preview']);
+
+    $element['preview'] = array(
+      '#type' => 'submit',
+      '#value' => t('Preview'),
+      '#access' => $preview_mode != DRUPAL_DISABLED,
+      '#submit' => array('comment_form_build_preview'),
+    );
+
+    $element['#weight'] = $form['comment_body']['#weight'] + 0.01;
+
+    return $element;
+  }
+
+  /**
    * @see Drupal\entity\EntityFormController::validate()
    */
   public function validate(array $form, array &$form_state) {
@@ -32,11 +59,11 @@ class CommentFormController extends EntityFormController {
   }
 
   /**
-   * @see Drupal\entity\EntityFormController::submit()
+   * @see Drupal\entity\EntityFormController::save()
    */
-  public function submit(array $form, array &$form_state) {
+  public function save(array $form, array &$form_state) {
     // Completely override the base method as we need to perform some advanced
-    // tweak before regularly build the entity from the submitted values.
+    // tweak before regularly building the entity from the submitted values.
     comment_form_submit($form, $form_state);
   }
 }
diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index 5ededc4..37819e4 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -6,7 +6,6 @@
  */
 
 use Drupal\entity\EntityInterface;
-use \Drupal\Core\Entity\FormController as EntityFormController;
 use Drupal\entity\EntityMalformedException;
 
 /**
@@ -72,9 +71,11 @@ function entity_get_info($entity_type = NULL) {
           'fieldable' => FALSE,
           'entity class' => 'Drupal\entity\Entity',
           'controller class' => 'Drupal\entity\DatabaseStorageController',
+          'form controller class' => array(
+            'default' => 'Drupal\entity\EntityFormController',
+          ),
           'static cache' => TRUE,
           'field cache' => TRUE,
-          'load hook' => $name . '_load',
           'bundles' => array(),
           'view modes' => array(),
           'entity keys' => array(),
@@ -458,27 +459,35 @@ function entity_form_field_validate($entity_type, $form, &$form_state) {
  *
  * @param $entity_type
  *   The type of the entity.
+ * @param
+ *   (optional) The bundle of the entity being edited.
  * @param $context
  *   (optional) The name of the context identifying the form controller.
  *
  * @return Drupal\entity\EntityFormController
  *   An instance of the Drupal\Core\Entity\FormController class.
  */
-function entity_get_form_controller($entity_type, $context = 'default') {
+function entity_get_form_controller($entity_type, $bundle = NULL, $context = 'default') {
   $info = entity_get_info($entity_type);
 
   // If no controller is specified default to the base implementation.
   if (!empty($info) && empty($info['form controller class'])) {
     $class = 'Drupal\entity\EntityFormController';
   }
+
+  // Check whether a bundle-specific form controller exists.
+  if (!empty($bundle) && !empty($info['bundle form controller class'][$bundle][$context])) {
+    $class = $info['bundle form controller class'][$bundle][$context];
+  }
+  // Fall back to the per-entity-type form controller.
+  elseif (!empty($info['form controller class'][$context])) {
+    $class = $info['form controller class'][$context];
+  }
   // If a non-existing context has been specified stop.
-  elseif (empty($info['form controller class'][$context])) {
+  else {
     // @todo Here we should throw an exception.
     return FALSE;
   }
-  else {
-    $class = $info['form controller class'][$context];
-  }
 
   return new $class($context);
 }
@@ -486,14 +495,17 @@ function entity_get_form_controller($entity_type, $context = 'default') {
 /**
  * Helper function. Returns the form id for the given entity.
  */
-function _entity_form_id(EntityInterface $entity) {
+function _entity_form_id(EntityInterface $entity, $context = 'default') {
   $entity_type = $entity->entityType();
   $bundle = $entity->bundle();
-  $form_id = $entity_type . '_form';
+  $form_id = $entity_type;
   if ($bundle != $entity_type) {
     $form_id = $bundle . '_' . $form_id;
   }
-  return $form_id;
+  if ($context != 'default') {
+    $form_id = $form_id . '_' . $context;
+  }
+  return $form_id . '_form';
 }
 
 /**
@@ -511,7 +523,7 @@ function entity_get_form($entity, $context = 'default') {
   if (is_string($entity)) {
     $entity = entity_create($entity, array());
   }
-  $form_id = _entity_form_id($entity);
+  $form_id = _entity_form_id($entity, $context);
   return drupal_get_form($form_id, $entity, $context);
 }
 
@@ -528,8 +540,8 @@ function entity_forms($form_id, $args) {
 
   if (!empty($args) && $args[0] instanceof EntityInterface) {
     try {
-      $entity = $args[0];
-      if ($form_id == _entity_form_id($entity)) {
+      list($entity, $context) = $args;
+      if ($form_id == _entity_form_id($entity, $context)) {
         $callback = 'entity_form';
         $forms[$form_id]['callback'] = $callback;
         $forms[$form_id]['base_form_ids'] = array($callback, $entity->entityType() . '_form');
@@ -544,10 +556,10 @@ function entity_forms($form_id, $args) {
 }
 
 /**
- * Form builder for any edit form.
+ * Form builder for any entity form.
  */
 function entity_form($form, &$form_state, EntityInterface $entity, $context) {
-  $controller = entity_get_form_controller($entity->entityType(), $context);
+  $controller = entity_get_form_controller($entity->entityType(), $entity->bundle(), $context);
   return $controller->build($form, $form_state, $entity);
 }
 
diff --git a/core/modules/entity/lib/Drupal/entity/Entity.php b/core/modules/entity/lib/Drupal/entity/Entity.php
index 627e8da..5b47228 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity.php
@@ -270,9 +270,8 @@ class Entity implements EntityInterface {
     return $this->isCurrentRevision;
   }
 
-
   /**
-   * Implements EntityInterface::edit().
+   * Implements EntityInterface::form().
    *
    * @param $context
    *   (optional) The context for the form to be returned.
diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormController.php b/core/modules/entity/lib/Drupal/entity/EntityFormController.php
index 8f7b906..15fc664 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityFormController.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityFormController.php
@@ -48,13 +48,28 @@ class EntityFormController {
    *   The array containing the complete form.
    */
   public final function build(array $form, array &$form_state, EntityInterface $entity) {
-    EntityFormController::setEntity($form_state, $entity);
+    // Set the entity form controller in the form state.
     EntityFormController::setFormInstance($form_state, $this);
 
+    // During initial form build, add the entity to the form state for use
+    // during form building and processing. During a rebuild, use what is in the
+    // form state.
+    $form_entity = EntityFormController::getEntity($form_state);
+    if (empty($form_entity)) {
+      EntityFormController::setEntity($form_state, $entity);
+    }
+    else {
+      $entity = $form_entity;
+    }
+
+    // Retrieve the form array.
     $form = $this->form($form, $form_state, $entity);
 
-    $form['#validate'][] = array($this, 'validate');
-    $form['#submit'][] = array($this, 'submit');
+    // Retrieve the form actions.
+    $actions = $this->actionsElement($form, $form_state, $entity);
+    if (!empty($actions)) {
+      $form['actions'] = $actions;
+    }
 
     return $form;
   }
@@ -75,6 +90,64 @@ class EntityFormController {
   }
 
   /**
+   * Returns the action form element for the current entity form.
+   */
+  protected final function actionsElement(array $form, array &$form_state, EntityInterface $entity) {
+    $element = $this->actions($form, $form_state, $entity);
+
+    // We cannot delete an entity that has not been created yet.
+    if (!$entity->id()) {
+      unset($element['delete']);
+    }
+    elseif (isset($element['delete'])) {
+      // Move the delete action as last one, unless weights are explictly
+      // provided.
+      $delete = $element['delete'];
+      unset($element['delete']);
+      $element['delete'] = $delete;
+    }
+
+    $count = 0;
+    $submit = array($this, 'submit');
+
+    foreach (element_children($element) as $action) {
+      $element[$action] += array(
+        '#type' => 'submit',
+        '#weight' => ++$count * 5,
+        '#validate' => array(),
+        '#submit' => array(),
+      );
+      // Ensure we always preprocess submitted data before calling the actual
+      // submission handlers.
+      array_unshift($element[$action]['#submit'], $submit);
+    }
+
+    if (!empty($element)) {
+      $element['#type'] = 'actions';
+    }
+
+    return $element;
+  }
+
+  /**
+   * Returns an array of supported actions for the current entity form.
+   */
+  protected function actions(array $form, array &$form_state, EntityInterface $entity) {
+    return array(
+      'submit' => array(
+        '#value' => t('Save'),
+        '#validate' => array(array($this, 'validate')),
+        '#submit' => array(array($this, 'save')),
+      ),
+      'delete' => array(
+        '#value' => t('Delete'),
+        // No need to validate the form when deleting the entity.
+        '#submit' => array(array($this, 'delete')),
+      ),
+    );
+  }
+
+  /**
    * Validates the submitted form values.
    *
    * @param $form
@@ -90,10 +163,15 @@ class EntityFormController {
     if (!empty($info['fieldable'])) {
       entity_form_field_validate($entity->entityType(), $form, $form_state);
     }
+
+    // @todo Remove this.
+    // Execute legacy global validation handlers.
+    unset($form_state['validate_handlers']);
+    form_execute_handlers('validate', $form, $form_state);
   }
 
   /**
-   * Processes the submitted form values.
+   * Processes the submitted form values and updates the entity object.
    *
    * @param $form
    *   An associative array containing the structure of the form.
@@ -101,14 +179,52 @@ class EntityFormController {
    *   A reference to a keyed array containing the current state of the form.
    */
   public function submit(array $form, array &$form_state) {
-    // @todo Exploit the Property API to process the values submitted for the
-    // entity properties.
+    // @todo Exploit the Property API to process the submitted  entity property
+    // values.
     $entity = EntityFormController::getEntity($form_state);
+    // @todo Do we really need this?
+    $this->prebuildEntity($form, $form_state);
+    // @todo Make entity_form_submit_build_entity() an entity form controller
+    // method.
     entity_form_submit_build_entity($entity->entityType(), $entity, $form, $form_state);
     EntityFormController::setEntity($form_state, $entity);
   }
 
   /**
+   * Gives a chance to manipulate submitted data before building the entity.
+   *
+   * @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.
+   */
+  protected function prebuildEntity(array $form, array &$form_state) {
+    if (isset($form['#entity_prebuilders'])) {
+      foreach ($form['#entity_prebuilders'] as $function) {
+        $function($form, $form_state);
+      }
+    }
+  }
+
+  /**
+   * Submit handler for the 'save' action.
+   *
+   * @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.
+   */
+  public function save(array $form, array &$form_state) {}
+
+  /**
+   * Submit handler for the 'delete' action.
+   *
+   * @param array $form
+   * @param array $form_state
+   */
+  public function delete(array $form, array &$form_state) {}
+
+  /**
    * Returns the code identifying the active form language.
    */
   public function getFormLangcode($form_state) {
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index ffdf8e0..f1c9a30 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -24,6 +24,25 @@ class NodeFormController extends EntityFormController {
   }
 
   /**
+   * @see Drupal\entity\EntityFormController::actions()
+   */
+  protected function actions(array $form, array &$form_state, EntityInterface $node) {
+    $element = parent::actions($form, $form_state, $node);
+    $preview_mode = variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL);
+
+    $element['preview'] = array(
+      '#access' => $preview_mode != DRUPAL_DISABLED,
+      '#value' => t('Preview'),
+      '#submit' => array('node_form_build_preview'),
+    );
+
+    $element['submit']['#access'] = $preview_mode != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview']));
+    $element['delete']['#access'] = node_access('delete', $node);
+
+    return $element;
+  }
+
+  /**
    * @see Drupal\entity\EntityFormController::validate()
    */
   public function validate(array $form, array &$form_state) {
@@ -35,8 +54,23 @@ class NodeFormController extends EntityFormController {
    * @see Drupal\entity\EntityFormController::submit()
    */
   public function submit(array $form, array &$form_state) {
-    // Completely override the base method as we need to perform some advanced
-    // tweak before regularly build the entity from the submitted values.
+    // Handle possible field translations first and then build the node from the
+    // submitted values.
+    node_field_language_form_submit($form, $form_state);
+    parent::submit($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\entity\EntityFormController::save()
+   */
+  public function save(array $form, array &$form_state) {
     node_form_submit($form, $form_state);
   }
+
+  /**
+   * @see Drupal\entity.EntityFormController::delete()
+   */
+  public function delete(array $form, array &$form_state) {
+    node_form_delete_submit($form, $form_state);
+  }
 }
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 9ff82f9..a319fb8 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -9,6 +9,8 @@
  * @see node_menu()
  */
 
+use Drupal\entity\EntityFormController;
+
 use Drupal\node\Node;
 
 /**
@@ -111,7 +113,7 @@ function node_form_validate($form, &$form_state) {
   // $form_state['node'] contains the actual entity being edited, but we must
   // not update it with form values that have not yet been validated, so we
   // create a pseudo-entity to use during validation.
-  $node = clone $form_state['node'];
+  $node = clone EntityFormController::getEntity($form_state);
   foreach ($form_state['values'] as $key => $value) {
     $node->{$key} = $value;
   }
@@ -325,42 +327,11 @@ function node_form($form, &$form_state, Node $node) {
     '#default_value' => $node->sticky,
   );
 
-  // Add the buttons.
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#access' => variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview'])),
-    '#value' => t('Save'),
-    '#weight' => 5,
-// TODO
-//     '#submit' => array('node_form_submit'),
-  );
-  $form['actions']['preview'] = array(
-    '#access' => variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_DISABLED,
-    '#type' => 'submit',
-    '#value' => t('Preview'),
-    '#weight' => 10,
-    '#submit' => array('node_form_build_preview'),
-  );
-  if (!empty($node->nid) && node_access('delete', $node)) {
-    $form['actions']['delete'] = array(
-      '#type' => 'submit',
-      '#value' => t('Delete'),
-      '#weight' => 15,
-      '#submit' => array('node_form_delete_submit'),
-    );
-  }
   // This form uses a button-level #submit handler for the form's main submit
   // action. node_form_submit() manually invokes all form-level #submit handlers
   // of the form. Without explicitly setting #submit, Form API would auto-detect
   // node_form_submit() as submit handler, but that is the button-level #submit
-  // handler for the 'Save' action. To maintain backwards compatibility, a
-  // #submit handler is auto-suggested for custom node type modules.
-// TODO
-//   $form['#validate'][] = 'node_form_validate';
-  if (!isset($form['#submit']) && function_exists($node->type . '_node_form_submit')) {
-    $form['#submit'][] = $node->type . '_node_form_submit';
-  }
+  // handler for the 'Save' action.
   $form += array('#submit' => array());
 
   return $form;
@@ -380,7 +351,7 @@ function node_form_delete_submit($form, &$form_state) {
     $destination = drupal_get_destination();
     unset($_GET['destination']);
   }
-  $node = $form['#node'];
+  $node = EntityFormController::getEntity($form_state);
   $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination));
 }
 
@@ -492,9 +463,6 @@ function theme_node_preview($variables) {
  * @see node_form_submit_build_node()
  */
 function node_form_submit($form, &$form_state) {
-  // Handle possible field translations first and then build the node from the
-  // submitted values.
-  node_field_language_form_submit($form, $form_state);
   $node = node_form_submit_build_node($form, $form_state);
   $insert = empty($node->nid);
   $node->save();
@@ -565,20 +533,7 @@ function node_field_language_form_submit($form, &$form_state) {
  * @see node_form_submit()
  */
 function node_form_submit_build_node($form, &$form_state) {
-  // @todo Legacy support for modules that extend the node form with form-level
-  //   submit handlers that adjust $form_state['values'] prior to those values
-  //   being used to update the entity. Module authors are encouraged to instead
-  //   adjust the node directly within a hook_node_submit() implementation. For
-  //   Drupal 8, evaluate whether the pattern of triggering form-level submit
-  //   handlers during button-level submit processing is worth supporting
-  //   properly, and if so, add a Form API function for doing so.
-  unset($form_state['submit_handlers']);
-  unset($form['#submit']);
-  form_execute_handlers('submit', $form, $form_state);
-
-  $node = $form_state['node'];
-  entity_form_submit_build_entity('node', $node, $form, $form_state);
-
+  $node = EntityFormController::getEntity($form_state);
   node_submit($node);
   foreach (module_implements('node_submit') as $module) {
     $function = $module . '_node_submit';
diff --git a/core/modules/poll/lib/Drupal/poll/PollFormController.php b/core/modules/poll/lib/Drupal/poll/PollFormController.php
new file mode 100644
index 0000000..7a53772
--- /dev/null
+++ b/core/modules/poll/lib/Drupal/poll/PollFormController.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\poll\PollFormController.
+ */
+
+namespace Drupal\poll;
+
+use Drupal\entity\EntityInterface;
+use Drupal\node\NodeFormController;
+
+/**
+ * Form controller for the node edit forms.
+ */
+class PollFormController extends NodeFormController {
+  // @todo Remove hook_form() and mmove form additions here.
+}
diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module
index 7954aaa..7a2131f 100644
--- a/core/modules/poll/poll.module
+++ b/core/modules/poll/poll.module
@@ -9,6 +9,13 @@
 use Drupal\node\Node;
 
 /**
+ * Implements hook_entity_info_alter().
+ */
+function poll_entity_info_alter(&$info) {
+  $info['node']['bundle form controller class']['poll']['default'] = 'Drupal\poll\PollFormController';
+}
+
+/**
  * Implements hook_help().
  */
 function poll_help($path, $arg) {
@@ -336,6 +343,8 @@ function poll_form(Node $node, &$form_state) {
     drupal_get_path('module', 'poll') . '/poll.admin.css',
   );
 
+  $form['#entity_prebuilders'][] = 'poll_node_form_submit';
+
   return $form;
 }
 
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
index d205b19..699cd64 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php
@@ -35,8 +35,14 @@ class TermFormController extends EntityFormController {
    * @see Drupal\entity\EntityFormController::submit()
    */
   public function submit(array $form, array &$form_state) {
-    // Completely override the base method as we need to perform some advanced
-    // tweak before regularly build the entity from the submitted values.
+    parent::submit($form, $form_state);
+    taxonomy_form_term_submit_build_taxonomy_term($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\entity\EntityFormController::save()
+   */
+  public function save(array $form, array &$form_state) {
     taxonomy_form_term_submit($form, $form_state);
   }
 }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php
index 1531aad..13096a1 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php
@@ -24,6 +24,14 @@ class VocabularyFormController extends EntityFormController {
   }
 
   /**
+   * Returns an array of supported actions for the current entity form.
+   */
+  protected function actions(array $form, array &$form_state, EntityInterface $entity) {
+    // If we are displaying the delete confirmation skip the regular actions.
+    return empty($form_state['confirm_delete']) ? parent::actions($form, $form_state, $entity) : array();
+  }
+
+  /**
    * @see Drupal\entity\EntityFormController::validate()
    */
   public function validate(array $form, array &$form_state) {
@@ -35,7 +43,20 @@ class VocabularyFormController extends EntityFormController {
    * @see Drupal\entity\EntityFormController::submit()
    */
   public function submit(array $form, array &$form_state) {
-    parent::submit($form, $form_state);
+    if ($form_state['triggering_element']['#value'] == t('Delete')) {
+      // Rebuild the form to confirm vocabulary deletion.
+      $form_state['rebuild'] = TRUE;
+      $form_state['confirm_delete'] = TRUE;
+    }
+    else {
+      parent::submit($form, $form_state);
+    }
+  }
+
+  /**
+   * @see Drupal\entity\EntityFormController::save()
+   */
+  public function save(array $form, array &$form_state) {
     taxonomy_form_vocabulary_submit($form, $form_state);
   }
 }
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index 21d34df..bd005e5 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -168,13 +168,9 @@ function taxonomy_form_vocabulary($form, &$form_state, Vocabulary $vocabulary =
     '#value' => '0',
   );
 
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
   if (isset($vocabulary->vid)) {
-    $form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
     $form['vid'] = array('#type' => 'value', '#value' => $vocabulary->vid);
   }
-  $form['#validate'][] = 'taxonomy_form_vocabulary_validate';
 
   return $form;
 }
@@ -208,13 +204,6 @@ function taxonomy_form_vocabulary_validate($form, &$form_state) {
  * @see taxonomy_form_vocabulary_validate()
  */
 function taxonomy_form_vocabulary_submit($form, &$form_state) {
-  if ($form_state['triggering_element']['#value'] == t('Delete')) {
-    // Rebuild the form to confirm vocabulary deletion.
-    $form_state['rebuild'] = TRUE;
-    $form_state['confirm_delete'] = TRUE;
-    return;
-  }
-
   $vocabulary = EntityFormController::getEntity($form_state);
 
   // Prevent leading and trailing spaces in vocabulary names.
@@ -776,23 +765,7 @@ function taxonomy_form_term($form, &$form_state, Term $term = NULL, Vocabulary $
     '#value' => $term->tid,
   );
 
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    '#weight' => 5,
-  );
-
-  if ($term->tid) {
-    $form['actions']['delete'] = array(
-      '#type' => 'submit',
-      '#value' => t('Delete'),
-      '#access' => taxonomy_term_access('delete', $term),
-      '#weight' => 10,
-      '#submit' => array('taxonomy_form_term_delete_submit'),
-    );
-  }
-  else {
+  if (empty($term->tid)) {
     $form_state['redirect'] = current_path();
   }
 
@@ -817,7 +790,7 @@ function taxonomy_form_term_validate($form, &$form_state) {
  * @see taxonomy_form_term()
  */
 function taxonomy_form_term_submit($form, &$form_state) {
-  $term = taxonomy_form_term_submit_build_taxonomy_term($form, $form_state);
+  $term = EntityFormController::getEntity($form_state);
 
   $status = taxonomy_term_save($term);
   switch ($status) {
@@ -861,8 +834,7 @@ function taxonomy_form_term_submit($form, &$form_state) {
  * Updates the form state's term entity by processing this submission's values.
  */
 function taxonomy_form_term_submit_build_taxonomy_term($form, &$form_state) {
-  $term = $form_state['term'];
-  entity_form_submit_build_entity('taxonomy_term', $term, $form, $form_state);
+  $term = EntityFormController::getEntity($form_state);
 
   // Prevent leading and trailing spaces in term names.
   $term->name = trim($term->name);
diff --git a/core/modules/user/lib/Drupal/user/ProfileFormController.php b/core/modules/user/lib/Drupal/user/ProfileFormController.php
index 486b38d..3b68090 100644
--- a/core/modules/user/lib/Drupal/user/ProfileFormController.php
+++ b/core/modules/user/lib/Drupal/user/ProfileFormController.php
@@ -19,22 +19,57 @@ class ProfileFormController extends EntityFormController {
    * @see Drupal\entity\EntityFormController::form()
    */
   protected function form(array $form, array &$form_state, EntityInterface $account) {
-    $form = user_profile_form($form, $form_state, $account);
+    // @todo Legacy support. Modules are encouraged to access the entity using
+    //   $form_state. Remove in Drupal 8.
+    $form['#user'] = $account;
+
+    user_account_form($form, $form_state);
+
     return parent::form($form, $form_state, $account);
   }
 
   /**
-   * @see Drupal\entity\EntityFormController::validate()
+   * @see Drupal\entity\EntityFormController::actions()
    */
-  public function validate(array $form, array &$form_state) {
-    user_profile_form_validate($form, $form_state);
-    parent::validate($form, $form_state);
+  protected function actions(array $form, array &$form_state, EntityInterface $account) {
+    $element = parent::actions($form, $form_state, $account);
+
+    // @todo Actually the cancel action can be assimilated to the delete one: we
+    // should alter it instead of providing a new one.
+    unset($element['delete']);
+
+    $element['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel account'),
+      '#submit' => array('user_edit_cancel_submit'),
+      '#access' => $account->uid > 1 && (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')),
+    );
+
+    return $element;
   }
 
   /**
    * @see Drupal\entity\EntityFormController::submit()
    */
   public function submit(array $form, array &$form_state) {
-    user_profile_form_submit($form, $form_state);
+    // @todo Consider moving this into the parent method.
+    // Remove unneeded values.
+    form_state_values_clean($form_state);
+    parent::submit($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\entity\EntityFormController::save()
+   */
+  public function save(array $form, array &$form_state) {
+    $account = EntityFormController::getEntity($form_state);
+    $account->save();
+    $form_state['values']['uid'] = $account->id();
+
+    // Clear the page cache because pages can contain usernames and/or profile
+    // information:
+    cache_invalidate(array('content' => TRUE));
+
+    drupal_set_message(t('The changes have been saved.'));
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php
index 7106dd3..1a590d2 100644
--- a/core/modules/user/lib/Drupal/user/RegisterFormController.php
+++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php
@@ -19,13 +19,44 @@ class RegisterFormController extends EntityFormController {
    * @see Drupal\entity\EntityFormController::form()
    */
   protected function form(array $form, array &$form_state, EntityInterface $account) {
-    return user_register_form($form, $form_state, $account);
+    return _user_register_form($form, $form_state, $account);
+  }
+
+  /**
+   * @see Drupal\entity\EntityFormController::actions()
+   */
+  protected function actions(array $form, array &$form_state, EntityInterface $account) {
+    $element = parent::actions($form, $form_state, $account);
+    $element['submit']['#value'] = t('Create new account');
+    return $element;
   }
 
   /**
    * @see Drupal\entity\EntityFormController::submit()
    */
   public function submit(array $form, array &$form_state) {
+    $admin = $form_state['values']['administer_users'];
+
+    if (!variable_get('user_email_verification', TRUE) || $admin) {
+      $pass = $form_state['values']['pass'];
+    }
+    else {
+      $pass = user_password();
+    }
+
+    // Remove unneeded values.
+    form_state_values_clean($form_state);
+
+    $form_state['values']['pass'] = $pass;
+    $form_state['values']['init'] = $form_state['values']['mail'];
+
+    parent::submit($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\entity\EntityFormController::submit()
+   */
+  public function save(array $form, array &$form_state) {
     user_register_submit($form, $form_state);
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/User.php b/core/modules/user/lib/Drupal/user/User.php
index 992923c..dd68536 100644
--- a/core/modules/user/lib/Drupal/user/User.php
+++ b/core/modules/user/lib/Drupal/user/User.php
@@ -141,4 +141,11 @@ class User extends Entity {
   public function id() {
     return $this->uid;
   }
+
+  /**
+   * Implements Drupal\entity\Entity::form()
+   */
+  public function form($context = 'profile') {
+    return parent::form($context);
+  }
 }
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 9365f56..f174a7f 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\entity\EntityFormController;
+
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\File\File;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -149,7 +151,7 @@ function user_entity_info() {
       'entity class' => 'Drupal\user\User',
       'controller class' => 'Drupal\user\UserStorageController',
       'form controller class' => array(
-        'default' => 'Drupal\user\ProfileFormController',
+        'profile' => 'Drupal\user\ProfileFormController',
         'register' => 'Drupal\user\RegisterFormController',
       ),
       'base table' => 'users',
@@ -1657,7 +1659,7 @@ function user_menu() {
   $items['user/%user/edit'] = array(
     'title' => 'Edit',
     'page callback' => 'entity_get_form',
-    'page arguments' => array(1),
+    'page arguments' => array(1, 'profile'),
     'access callback' => 'user_edit_access',
     'access arguments' => array(1),
     'type' => MENU_LOCAL_TASK,
@@ -3492,7 +3494,7 @@ function user_form_field_ui_field_edit_form_submit($form, &$form_state) {
  * @see user_account_form_validate()
  * @see user_register_submit()
  */
-function user_register_form($form, &$form_state) {
+function _user_register_form($form, &$form_state) {
   global $user;
 
   $admin = user_access('administer users');
@@ -3533,43 +3535,21 @@ function user_register_form($form, &$form_state) {
     $form_state['redirect'] = current_path();
   }
 
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Create new account'),
-  );
-
   return $form;
 }
 
 /**
  * Submit handler for the user registration form.
  *
- * This function is shared by the installation form and the normal registration form,
- * which is why it can't be in the user.pages.inc file.
- *
- * @see user_register_form()
+ * This function is shared by the installation form and the normal registration
+ * form, which is why it can't be in the user.pages.inc file.
  */
 function user_register_submit($form, &$form_state) {
+  $account = EntityFormController::getEntity($form_state);
+  $pass = $account->pass;
   $admin = $form_state['values']['administer_users'];
-
-  if (!variable_get('user_email_verification', TRUE) || $admin) {
-    $pass = $form_state['values']['pass'];
-  }
-  else {
-    $pass = user_password();
-  }
   $notify = !empty($form_state['values']['notify']);
 
-  // Remove unneeded values.
-  form_state_values_clean($form_state);
-
-  $form_state['values']['pass'] = $pass;
-  $form_state['values']['init'] = $form_state['values']['mail'];
-
-  $account = $form['#user'];
-
-  entity_form_submit_build_entity('user', $account, $form, $form_state);
   $status = $account->save();
 
   // Terminate if an error occurred while saving the account.
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index bf3197f..970fafc 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -5,6 +5,8 @@
  * User page callback file for the user module.
  */
 
+use Drupal\entity\EntityFormController;
+
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 
 /**
@@ -201,79 +203,6 @@ function template_preprocess_user_profile(&$variables) {
 }
 
 /**
- * Form builder; edit a user account.
- *
- * @ingroup forms
- * @see user_account_form()
- * @see user_account_form_validate()
- * @see user_profile_form_validate()
- * @see user_profile_form_submit()
- * @see user_cancel_confirm_form_submit()
- */
-function user_profile_form($form, &$form_state, $account) {
-  global $user;
-
-  // During initial form build, add the entity to the form state for use during
-  // form building and processing. During a rebuild, use what is in the form
-  // state.
-  if (!isset($form_state['user'])) {
-    $form_state['user'] = $account;
-  }
-  else {
-    $account = $form_state['user'];
-  }
-
-  // @todo Legacy support. Modules are encouraged to access the entity using
-  //   $form_state. Remove in Drupal 8.
-  $form['#user'] = $account;
-
-  user_account_form($form, $form_state);
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-  );
-  $form['actions']['cancel'] = array(
-    '#type' => 'submit',
-    '#value' => t('Cancel account'),
-    '#submit' => array('user_edit_cancel_submit'),
-    '#access' => $account->uid > 1 && (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')),
-  );
-
-  return $form;
-}
-
-/**
- * Validation function for the user account and profile editing form.
- */
-function user_profile_form_validate($form, &$form_state) {
-  entity_form_field_validate('user', $form, $form_state);
-}
-
-/**
- * Submit function for the user account and profile editing form.
- */
-function user_profile_form_submit($form, &$form_state) {
-  $account = $form_state['user'];
-  // Remove unneeded values.
-  form_state_values_clean($form_state);
-
-  entity_form_submit_build_entity('user', $account, $form, $form_state);
-  $account->save();
-  $form_state['values']['uid'] = $account->uid;
-
-  if (!empty($edit['pass'])) {
-    // Remove the password reset tag since a new password was saved.
-    unset($_SESSION['pass_reset_'. $account->uid]);
-  }
-  // Clear the page cache because pages can contain usernames and/or profile information:
-  cache_invalidate(array('content' => TRUE));
-
-  drupal_set_message(t('The changes have been saved.'));
-}
-
-/**
  * Submit function for the 'Cancel account' button on the user edit form.
  */
 function user_edit_cancel_submit($form, &$form_state) {
