diff --git a/core/includes/form.inc b/core/includes/form.inc
index c1d48e3..32199fb 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -763,7 +763,14 @@ function drupal_retrieve_form($form_id, &$form_state) {
     }
     if (isset($form_definition['callback'])) {
       $callback = $form_definition['callback'];
-      $form_state['build_info']['base_form_id'] = $callback;
+      if (empty($form_definition['base_form_ids'])) {
+        $form_definition['base_form_ids'] = array($callback);
+      }
+      // The most specific base form id will be used as the main one.
+      $form_state['build_info']['base_form_id'] = end($form_definition['base_form_ids']);
+      // Store the additional base form ids to allow for more generic or
+      // granular form altering.
+      $form_state['build_info']['base_form_ids'] = $form_definition['base_form_ids'];
     }
     // In case $form_state['wrapper_callback'] is not defined already, we also
     // allow hook_forms() to define one.
@@ -1070,8 +1077,10 @@ function drupal_prepare_form($form_id, &$form, &$form_state) {
   // Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and
   // hook_form_FORM_ID_alter() implementations.
   $hooks = array('form');
-  if (isset($form_state['build_info']['base_form_id'])) {
-    $hooks[] = 'form_' . $form_state['build_info']['base_form_id'];
+  if (isset($form_state['build_info']['base_form_ids'])) {
+    foreach ($form_state['build_info']['base_form_ids'] as $base_form_id) {
+      $hooks[] = 'form_' . $base_form_id;
+    }
   }
   $hooks[] = 'form_' . $form_id;
   drupal_alter($hooks, $form, $form_state, $form_id);
@@ -1450,7 +1459,7 @@ function form_execute_handlers($type, &$form, &$form_state) {
       $batch['has_form_submits'] = TRUE;
     }
     else {
-      $function($form, $form_state);
+      call_user_func_array($function, array($form, &$form_state));
     }
     $return = TRUE;
   }
diff --git a/core/lib/Drupal/Core/Entity/FormController.php b/core/lib/Drupal/Core/Entity/FormController.php
new file mode 100644
index 0000000..6d834e8
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/FormController.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Entity\FormController.
+ */
+
+namespace Drupal\Core\Entity;
+
+/**
+ * Base for controller for entity edit forms.
+ */
+class FormController {
+
+  /**
+   * The name of the current context.
+   *
+   * Subclasses may use this value to implement different behaviors depending on
+   * this value.
+   *
+   * @var string
+   */
+  protected $context;
+
+  /**
+   * Returns the type of the entity being edited.
+   */
+  public static final function getEntityType($form_state) {
+    return isset($form_state['entity_type']) ? $form_state['entity_type'] : FALSE;
+  }
+
+  /**
+   * Returns the entity being edited.
+   */
+  public static final function getEntity($form_state) {
+    return isset($form_state['entity']) ? $form_state['entity'] : FALSE;
+  }
+
+  /**
+   * Stores the entity being edited.
+   */
+  public static final function setEntity($form_state, $entity) {
+    return $form_state['entity'] = $entity;
+  }
+
+  /**
+   * Returns an instance of the form controller associated with the form being edited.
+   */
+  public static function getFormInstance($form_state) {
+    return isset($form_state['entity_form_controller']) ? $form_state['entity_form_controller'] : FALSE;
+  }
+
+  /**
+   * Associates the current form controller to the form being edited.
+   */
+  public function setFormInstance(&$form_state) {
+    $form_state['entity_form_controller'] = $this;
+  }
+
+  /**
+   * Constructs a FormController object.
+   *
+   * @param string $context
+   *   The name of the current context.
+   */
+  public function __construct($context) {
+    $this->context = $context;
+  }
+
+  /**
+   * Builds an entity edit form.
+   *
+   * @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.
+   * @param $entity_type
+   *   The type of the entity being edited.
+   * @param $entity
+   *   The entity being edited.
+   *
+   * @return
+   *   The array containing the complete form.
+   */
+  public final function build(array $form, array &$form_state, $entity_type, $entity) {
+    $form_state['entity_type'] = $entity_type;
+    $form_state['entity'] = $entity;
+
+    $this->setFormInstance($form_state);
+    $form = $this->form($form, $form_state, $entity_type, $entity);
+
+    $form['#validate'][] = array($this, 'validate');
+    $form['#submit'][] = array($this, 'submit');
+
+    return $form;
+  }
+
+  /**
+   * Retuerns the actualform array to be built.
+   *
+   * @see FormController::build().
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $entity) {
+    // @todo Exploit the Property API to generate the default widgets for the
+    // entity properties.
+    $info = entity_get_info($entity_type);
+    if (!empty($info['fieldable'])) {
+      field_attach_form($entity_type, $entity, $form, $form_state, $this->getFormLangcode($form_state));
+    }
+    return $form;
+  }
+
+  /**
+   * Validates the submitted form values.
+   *
+   * @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 validate(array $form, array &$form_state) {
+    // @todo Exploit the Property API to validate the values submitted for the
+    // entity properties.
+    $info = entity_get_info($this->getEntityType($form_state));
+    if (!empty($info['fieldable'])) {
+      entity_form_field_validate($this->getEntityType($form_state), $form, $form_state);
+    }
+  }
+
+  /**
+   * Processes the submitted form values.
+   *
+   * @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 submit(array $form, array &$form_state) {
+    // @todo Exploit the Property API to process the values submitted for the
+    // entity properties.
+    $entity = $this->getEntity($form_state);
+    entity_form_submit_build_entity($this->getEntityType($form_state), $entity, $form, $form_state);
+    $this->setEntity($form_state, $entity);
+  }
+
+  /**
+   * Returns the code identifying the active form language. 
+   */
+  public function getFormLangcode($form_state) {
+    // @todo Introduce a new language type to use as the default language.
+    $entity = $this->getEntity($form_state);
+    return isset($entity->langcode) ? $entity->langcode : LANGUAGE_NOT_SPECIFIED;
+  }
+}
diff --git a/core/lib/Drupal/Module/Comment/FormController.php b/core/lib/Drupal/Module/Comment/FormController.php
new file mode 100644
index 0000000..16e4e7b
--- /dev/null
+++ b/core/lib/Drupal/Module/Comment/FormController.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Module\Comment\FormController.
+ */
+
+namespace Drupal\Module\Comment;
+
+/**
+ * Base for controller for entity edit forms.
+ */
+class FormController extends \Drupal\Core\Entity\FormController {
+
+  /**
+   * @see Drupal\Core\Entity\FormController::form()
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $comment) {
+    $form = comment_form($form, $form_state, $comment);
+    return parent::form($form, $form_state, $entity_type, $comment);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::validate()
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+    comment_form_validate($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::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.
+    comment_form_submit($form, $form_state);
+  }
+}
diff --git a/core/lib/Drupal/Module/Node/FormController.php b/core/lib/Drupal/Module/Node/FormController.php
new file mode 100644
index 0000000..be1be51
--- /dev/null
+++ b/core/lib/Drupal/Module/Node/FormController.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Module\Node\FormController.
+ */
+
+namespace Drupal\Module\Node;
+
+/**
+ * Form controller for the node edit forms.
+ */
+class FormController extends \Drupal\Core\Entity\FormController {
+
+  /**
+   * @see Drupal\Core\Entity\FormController::form()
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $node) {
+    $form = node_form($form, $form_state, $node);
+    return parent::form($form, $form_state, $entity_type, $node);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::validate()
+   */
+  public function validate(array $form, array &$form_state) {
+    node_form_validate($form, $form_state);
+    parent::validate($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::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.
+    node_form_submit($form, $form_state);
+  }
+}
diff --git a/core/lib/Drupal/Module/Taxonomy/TermFormController.php b/core/lib/Drupal/Module/Taxonomy/TermFormController.php
new file mode 100644
index 0000000..923c34c
--- /dev/null
+++ b/core/lib/Drupal/Module/Taxonomy/TermFormController.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Module\Taxonomy\TermFormController.
+ */
+
+namespace Drupal\Module\Taxonomy;
+
+/**
+ * Base for controller for entity edit forms.
+ */
+class TermFormController extends \Drupal\Core\Entity\FormController {
+
+  /**
+   * @see Drupal\Core\Entity\FormController::form()
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $term) {
+    $form = taxonomy_form_term($form, $form_state, $term);
+    return parent::form($form, $form_state, $entity_type, $term);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::validate()
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+    taxonomy_form_term_validate($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::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.
+    taxonomy_form_term_submit($form, $form_state);
+  }
+}
diff --git a/core/lib/Drupal/Module/Taxonomy/VocabularyFormController.php b/core/lib/Drupal/Module/Taxonomy/VocabularyFormController.php
new file mode 100644
index 0000000..f0a0f1c
--- /dev/null
+++ b/core/lib/Drupal/Module/Taxonomy/VocabularyFormController.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Module\Taxonomy\VocabularyFormController.
+ */
+
+namespace Drupal\Module\Taxonomy;
+
+/**
+ * Base for controller for entity edit forms.
+ */
+class VocabularyFormController extends \Drupal\Core\Entity\FormController {
+
+  /**
+   * @see Drupal\Core\Entity\FormController::form()
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $term) {
+    $form = taxonomy_form_vocabulary($form, $form_state, $term);
+    return parent::form($form, $form_state, $entity_type, $term);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::validate()
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+    taxonomy_form_vocabulary_validate($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::submit()
+   */
+  public function submit(array $form, array &$form_state) {
+    parent::submit($form, $form_state);
+    taxonomy_form_vocabulary_submit($form, $form_state);
+  }
+}
diff --git a/core/lib/Drupal/Module/User/ProfileFormController.php b/core/lib/Drupal/Module/User/ProfileFormController.php
new file mode 100644
index 0000000..ed4da60
--- /dev/null
+++ b/core/lib/Drupal/Module/User/ProfileFormController.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Module\User\ProfileFormController.
+ */
+
+namespace Drupal\Module\User;
+
+/**
+ * Form controller for the node edit forms.
+ */
+class ProfileFormController extends \Drupal\Core\Entity\FormController {
+
+  /**
+   * @see Drupal\Core\Entity\FormController::form()
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $node) {
+    $form = user_profile_form($form, $form_state, $node);
+    return parent::form($form, $form_state, $entity_type, $node);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::validate()
+   */
+  public function validate(array $form, array &$form_state) {
+    user_profile_form_validate($form, $form_state);
+    parent::validate($form, $form_state);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::submit()
+   */
+  public function submit(array $form, array &$form_state) {
+    user_profile_form_submit($form, $form_state);
+  }
+}
diff --git a/core/lib/Drupal/Module/User/RegisterFormController.php b/core/lib/Drupal/Module/User/RegisterFormController.php
new file mode 100644
index 0000000..bcddd36
--- /dev/null
+++ b/core/lib/Drupal/Module/User/RegisterFormController.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Module\User\RegisterFormController.
+ */
+
+namespace Drupal\Module\User;
+
+/**
+ * Form controller for the node edit forms.
+ */
+class RegisterFormController extends \Drupal\Core\Entity\FormController {
+
+  /**
+   * @see Drupal\Core\Entity\FormController::form()
+   */
+  protected function form(array $form, array &$form_state, $entity_type, $node) {
+    return user_register_form($form, $form_state, $node);
+  }
+
+  /**
+   * @see Drupal\Core\Entity\FormController::submit()
+   */
+  public function submit(array $form, array &$form_state) {
+    user_register_submit($form, $form_state);
+  }
+}
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 1a3580f..d6f2da7 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -99,6 +99,9 @@ function comment_entity_info() {
       'uri callback' => 'comment_uri',
       'fieldable' => TRUE,
       'controller class' => 'CommentStorageController',
+      'form controller class' => array(
+        'default' => '\\Drupal\\Module\\Comment\FormController',
+      ),
       'entity class' => 'Comment',
       'entity keys' => array(
         'id' => 'cid',
@@ -764,8 +767,7 @@ function comment_node_page_additions($node) {
 
   // Append comment form if needed.
   if (user_access('post comments') && $node->comment == COMMENT_NODE_OPEN && (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_BELOW)) {
-    $comment = entity_create('comment', array('nid' => $node->nid));
-    $additions['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", $comment);
+    $additions['comment_form'] = comment_edit($node);
   }
 
   if ($additions) {
@@ -781,6 +783,14 @@ function comment_node_page_additions($node) {
 }
 
 /**
+ * Returns a rendered form to comment the given node.
+ */
+function comment_edit($node, $pid = NULL) {
+  $values = array('nid' => $node->nid, 'pid' => $pid, 'node_type' => 'comment_node_' . $node->type);
+  return entity_create('comment', $values)->edit();
+}
+
+/**
  * Retrieves comments for a thread.
  *
  * @param $node
@@ -1650,19 +1660,7 @@ function comment_get_display_page($cid, $node_type) {
  */
 function comment_edit_page($comment) {
   drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject)), PASS_THROUGH);
-  $node = node_load($comment->nid);
-  return drupal_get_form("comment_node_{$node->type}_form", $comment);
-}
-
-/**
- * Implements hook_forms().
- */
-function comment_forms() {
-  $forms = array();
-  foreach (node_type_get_types() as $type) {
-    $forms["comment_node_{$type->type}_form"]['callback'] = 'comment_form';
-  }
-  return $forms;
+  return $comment->edit();
 }
 
 /**
@@ -1870,7 +1868,6 @@ function comment_form($form, &$form_state, $comment) {
 
   // Attach fields.
   $comment->node_type = 'comment_node_' . $node->type;
-  field_attach_form('comment', $comment, $form, $form_state);
 
   return $form;
 }
@@ -1951,8 +1948,6 @@ function comment_preview($comment) {
 function comment_form_validate($form, &$form_state) {
   global $user;
 
-  entity_form_field_validate('comment', $form, $form_state);
-
   if (!empty($form_state['values']['cid'])) {
     // Verify the name in case it is being changed from being anonymous.
     $account = user_load_by_name($form_state['values']['name']);
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index 344e757..42b63e4 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -35,8 +35,7 @@ function comment_reply($node, $pid = NULL) {
   // The user is previewing a comment prior to submitting it.
   if ($op == t('Preview')) {
     if (user_access('post comments')) {
-      $comment = entity_create('comment', array('nid' => $node->nid, 'pid' => $pid));
-      $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", $comment);
+      $build['comment_form'] = comment_edit($node, $pid);
     }
     else {
       drupal_set_message(t('You are not authorized to post comments.'), 'error');
@@ -87,8 +86,7 @@ function comment_reply($node, $pid = NULL) {
       drupal_goto("node/$node->nid");
     }
     elseif (user_access('post comments')) {
-      $comment = entity_create('comment', array('nid' => $node->nid, 'pid' => $pid));
-      $build['comment_form'] = drupal_get_form("comment_node_{$node->type}_form", $comment);
+      $build['comment_form'] = comment_edit($node, $pid);
     }
     else {
       drupal_set_message(t('You are not authorized to post comments.'), 'error');
diff --git a/core/modules/entity/entity.api.php b/core/modules/entity/entity.api.php
index e983778..e1406f9 100644
--- a/core/modules/entity/entity.api.php
+++ b/core/modules/entity/entity.api.php
@@ -24,6 +24,12 @@
  *   - controller class: The name of the class that is used to load the objects.
  *     The class has to implement the DrupalEntityControllerInterface interface.
  *     Leave blank to use the DrupalDefaultEntityController implementation.
+ *   - form controller class: An array of form controller class names keyed by
+ *     context name. Each class handle the edit form for the entity being
+ *     defined, alongside with its handlers, for the related context. The
+ *     context is also passed to the class costructor hence if only small tweaks
+ *     are needed to adapt the edit form to the various contexts a unique class
+ *     may be provided.
  *   - base table: (used by DrupalDefaultEntityController) The name of the
  *     entity type's base table.
  *   - static cache: (used by DrupalDefaultEntityController) FALSE to disable
@@ -130,6 +136,9 @@ function hook_entity_info() {
     'node' => array(
       'label' => t('Node'),
       'controller class' => 'NodeController',
+      'form controller' => array(
+        'default' => '\\Drupal\\Module\\Node\\FormController',
+      ),
       'base table' => 'node',
       'revision table' => 'node_revision',
       'uri callback' => 'node_uri',
diff --git a/core/modules/entity/entity.class.inc b/core/modules/entity/entity.class.inc
index 9b13256..cded48b 100644
--- a/core/modules/entity/entity.class.inc
+++ b/core/modules/entity/entity.class.inc
@@ -107,6 +107,11 @@ interface EntityInterface {
    * @see entity_get_info()
    */
   public function entityInfo();
+
+  /**
+   * Returns a rendered entity edit form.
+   */
+  public function edit();
 }
 
 /**
@@ -277,6 +282,15 @@ class Entity implements EntityInterface {
   }
 
   /**
+   * Implements EntityInterface::edit().
+   */
+  public function edit() {
+    // @todo Move entity_edit() here as soon as all core entities are subclasses
+    // of the Entity class.
+    return entity_edit($this->entityType, $this);
+  }
+
+  /**
    * Serializes only what is necessary.
    *
    * See @link http://www.php.net/manual/language.oop5.magic.php#language.oop5.magic.sleep PHP Magic Methods @endlink.
diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index fe9a6e5..5f5d71c 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -5,6 +5,8 @@
  * Entity API for handling entities like nodes or users.
  */
 
+use \Drupal\Core\Entity\FormController as EntityFormController;
+
 /**
  * Implements hook_help().
  */
@@ -428,6 +430,112 @@ function entity_form_field_validate($entity_type, $form, &$form_state) {
 }
 
 /**
+ * Returns a form controller for the given context.
+ *
+ * Since there might be different contexts in which an entity or parts of it are
+ * edited, multiple form controllers suitable to the different contexts may be
+ * defined. If no valid controller is found for the given context the default
+ * one will be used.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $context
+ *   (optional) The name of the context identifying the form controller.
+ *
+ * @return Drupal\Core\Entity\FormController
+ *   An instance of the Drupal\Core\Entity\FormController class.
+ */
+function entity_form_controller($entity_type, $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\\Core\\Entity\\FormController';
+  }
+  // If a non-existing context has been specified stop. 
+  elseif (empty($info['form controller class'][$context])) {
+    // @todo Here we should throw an exception.
+    return FALSE;
+  }
+  else {
+    $class = $info['form controller class'][$context];
+  }
+
+  return new $class($context);
+}
+
+/**
+ * Helper function. Returns the form id for the given entity.
+ */
+function _entity_form_id($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  $form_id = $entity_type . '_form';
+  if ($bundle != $entity_type) {
+    $form_id = $bundle . '_' . $form_id;
+  }
+  return $form_id;
+}
+
+/**
+ * Returns a rendered edit form for the given entity and context.
+ *
+ * @param $entity_type
+ *   The type of the entity being edited.
+ * @param $entity
+ *   The entity being edited.
+ * @param $context
+ *   (optional) The context for the form to be returned.
+ *
+ * @return
+ *   A rendered edit form for the given entity.
+ */
+function entity_edit($entity_type, $entity = NULL, $context = 'default') {
+  if (empty($entity)) {
+    $entity = new stdClass();
+  }
+  $form_id = _entity_form_id($entity_type, $entity);
+  return drupal_get_form($form_id, $entity_type, $entity, $context);
+}
+
+/**
+ * Implements hook_forms().
+ *
+ * Returns the generic 'entity_form' callback and defines the additional
+ * ENTITY_TYPE_form base id to allow for both generic and entity-specific form
+ * alterations. This we have three levels of granularity: bundle, entity type,
+ * all.
+ */
+function entity_forms($form_id, $args) {
+  $forms = array();
+
+  // Proceed only when the argument types match the ones defined in the
+  // signature of entity_edit().
+  if (count($args) == 3 && is_string($args[0]) && is_object($args[1])) {
+    try {
+      list($entity_type, $entity) = $args;
+      if ($form_id == _entity_form_id($entity_type, $entity)) {
+        $callback = 'entity_form';
+        $forms[$form_id]['callback'] = $callback;
+        $forms[$form_id]['base_form_ids'] = array($callback, $entity_type . '_form');
+      }
+    }
+    catch (EntityMalformedException $e) {
+      // Not an entity form, exit silently.
+    }
+  }
+
+  return $forms;
+}
+
+/**
+ * Form builder for any edit form.
+ */
+function entity_form($form, &$form_state, $entity_type, $entity, $context) {
+  $controller = entity_form_controller($entity_type, $context);
+  return $controller->build($form, $form_state, $entity_type, $entity);
+}
+
+/**
  * Copies submitted values to entity properties for simple entity forms.
  *
  * During the submission handling of an entity form's "Save", "Preview", and
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index be60e48..7a7062c 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -184,6 +184,9 @@ function node_entity_info() {
     'node' => array(
       'label' => t('Node'),
       'controller class' => 'NodeController',
+      'form controller class' => array(
+        'default' => '\\Drupal\\Module\\Node\\FormController',
+      ),
       'base table' => 'node',
       'revision table' => 'node_revision',
       'uri callback' => 'node_uri',
@@ -2118,7 +2121,7 @@ function node_menu() {
     'weight' => -10,
   );
   $items['node/%node/edit'] = array(
-    'title' => 'Edit',
+    'title' => 'edit',
     'page callback' => 'node_page_edit',
     'page arguments' => array(1),
     'access callback' => 'node_access',
@@ -3747,21 +3750,6 @@ function node_content_form($node, $form_state) {
  */
 
 /**
- * Implements hook_forms().
- *
- * All node forms share the same form handler.
- */
-function node_forms() {
-  $forms = array();
-  if ($types = node_type_get_types()) {
-    foreach (array_keys($types) as $type) {
-      $forms[$type . '_node_form']['callback'] = 'node_form';
-    }
-  }
-  return $forms;
-}
-
-/**
  * Implements hook_action_info().
  */
 function node_action_info() {
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 4e94b26..d2971b3 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -18,7 +18,7 @@
 function node_page_edit($node) {
   $type_name = node_type_get_name($node);
   drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => $type_name, '@title' => $node->title)), PASS_THROUGH);
-  return drupal_get_form($node->type . '_node_form', $node);
+  return entity_edit('node', $node);
 }
 
 /**
@@ -83,7 +83,7 @@ function node_add($type) {
   $types = node_type_get_types();
   $node = (object) array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'langcode' => LANGUAGE_NOT_SPECIFIED);
   drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
-  $output = drupal_get_form($type . '_node_form', $node);
+  $output = entity_edit('node', $node);
 
   return $output;
 }
@@ -102,7 +102,6 @@ function node_form_validate($form, &$form_state) {
   // create a pseudo-entity to use during validation.
   $node = (object) $form_state['values'];
   node_validate($node, $form, $form_state);
-  entity_form_field_validate('node', $form, $form_state);
 }
 
 /**
@@ -323,7 +322,7 @@ function node_form($form, &$form_state, $node) {
     '#access' => variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview'])),
     '#value' => t('Save'),
     '#weight' => 5,
-    '#submit' => array('node_form_submit'),
+//     '#submit' => array('node_form_submit'),
   );
   $form['actions']['preview'] = array(
     '#access' => variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL) != DRUPAL_DISABLED,
@@ -346,13 +345,12 @@ function node_form($form, &$form_state, $node) {
   // 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.
-  $form['#validate'][] = 'node_form_validate';
+//   $form['#validate'][] = 'node_form_validate';
   if (!isset($form['#submit']) && function_exists($node->type . '_node_form_submit')) {
     $form['#submit'][] = $node->type . '_node_form_submit';
   }
   $form += array('#submit' => array());
 
-  field_attach_form('node', $node, $form, $form_state, $node->langcode);
   return $form;
 }
 
@@ -536,6 +534,7 @@ function node_form_submit_build_node($form, &$form_state) {
   //   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'];
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 00c75c7..1b32faf 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -1341,9 +1341,10 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
  * @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().
+ *   - base form ids: An array containing a list of base form ids to be used to
+ *     alter the form using hook_form_BASE_FORM_ID_alter(). If no value is
+ *     provided the callback function name will be used.
+ *   - callback: The name of the form builder function to invoke.
  *   - 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
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index beb87f9..48186e7 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -5,6 +5,8 @@
  * Administrative page callbacks for the taxonomy module.
  */
 
+use \Drupal\Core\Entity\FormController as EntityFormController;
+
 /**
  * Form builder to list and manage vocabularies.
  *
@@ -219,8 +221,7 @@ function taxonomy_form_vocabulary_submit($form, &$form_state) {
     return;
   }
 
-  $vocabulary = $form_state['vocabulary'];
-  entity_form_submit_build_entity('taxonomy_vocabulary', $vocabulary, $form, $form_state);
+  $vocabulary = EntityFormController::getEntity($form_state);
 
   switch (taxonomy_vocabulary_save($vocabulary)) {
     case SAVED_NEW:
@@ -642,6 +643,14 @@ function theme_taxonomy_overview_terms($variables) {
 }
 
 /**
+ * Returns a rendered edit form to create a new term associated to the given vocabulary.
+ */
+function taxonomy_term_edit($vocabulary) {
+  $term = (object) array('vid' => $vocabulary->vid, 'vocabulary_machine_name' => $vocabulary->machine_name);
+  return entity_edit('taxonomy_term', $term);
+}
+
+/**
  * Form function for the term edit form.
  *
  * @ingroup forms
@@ -708,8 +717,6 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary =
     '#value' => isset($term->vocabulary_machine_name) ? $term->vocabulary_machine_name : $vocabulary->name,
   );
 
-  field_attach_form('taxonomy_term', $term, $form, $form_state);
-
   $form['relations'] = array(
     '#type' => 'fieldset',
     '#title' => t('Relations'),
@@ -797,8 +804,6 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary =
  * @see taxonomy_form_term()
  */
 function taxonomy_form_term_validate($form, &$form_state) {
-  entity_form_field_validate('taxonomy_term', $form, $form_state);
-
   // Ensure numeric values.
   if (isset($form_state['values']['weight']) && !is_numeric($form_state['values']['weight'])) {
     form_set_error('weight', t('Weight value must be numeric.'));
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 47cde42..d4326f6 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -108,6 +108,9 @@ function taxonomy_entity_info() {
     'taxonomy_term' => array(
       'label' => t('Taxonomy term'),
       'controller class' => 'TaxonomyTermController',
+      'form controller class' => array(
+        'default' => '\\Drupal\\Module\\Taxonomy\\TermFormController',
+      ),
       'base table' => 'taxonomy_term_data',
       'uri callback' => 'taxonomy_term_uri',
       'fieldable' => TRUE,
@@ -143,6 +146,9 @@ function taxonomy_entity_info() {
   $return['taxonomy_vocabulary'] = array(
     'label' => t('Taxonomy vocabulary'),
     'controller class' => 'TaxonomyVocabularyController',
+    'form controller class' => array(
+        'default' => '\\Drupal\\Module\\Taxonomy\\VocabularyFormController',
+    ),
     'base table' => 'taxonomy_vocabulary',
     'entity keys' => array(
       'id' => 'vid',
@@ -287,8 +293,8 @@ function taxonomy_menu() {
   );
   $items['admin/structure/taxonomy/add'] = array(
     'title' => 'Add vocabulary',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('taxonomy_form_vocabulary'),
+    'page callback' => 'entity_edit',
+    'page arguments' => array('taxonomy_vocabulary'),
     'access arguments' => array('administer taxonomy'),
     'type' => MENU_LOCAL_ACTION,
     'file' => 'taxonomy.admin.inc',
@@ -309,10 +315,10 @@ function taxonomy_menu() {
   );
   $items['taxonomy/term/%taxonomy_term/edit'] = array(
     'title' => 'Edit',
-    'page callback' => 'drupal_get_form',
+    'page callback' => 'entity_edit',
     // Pass a NULL argument to ensure that additional path components are not
     // passed to taxonomy_form_term() as the vocabulary machine name argument.
-    'page arguments' => array('taxonomy_form_term', 2, NULL),
+    'page arguments' => array('taxonomy_term', 2),
     'access callback' => 'taxonomy_term_access',
     'access arguments' => array('edit', 2),
     'type' => MENU_LOCAL_TASK,
@@ -362,8 +368,8 @@ function taxonomy_menu() {
   );
   $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/edit'] = array(
     'title' => 'Edit',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('taxonomy_form_vocabulary', 3),
+    'page callback' => 'entity_edit',
+    'page arguments' => array('taxonomy_vocabulary', 3),
     'access arguments' => array('administer taxonomy'),
     'type' => MENU_LOCAL_TASK,
     'weight' => -10,
@@ -372,8 +378,8 @@ function taxonomy_menu() {
 
   $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add'] = array(
     'title' => 'Add term',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('taxonomy_form_term', array(), 3),
+    'page callback' => 'taxonomy_term_edit',
+    'page arguments' => array(3),
     'access arguments' => array('administer taxonomy'),
     'type' => MENU_LOCAL_ACTION,
     'file' => 'taxonomy.admin.inc',
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index f7d4552..be533a1 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -11,7 +11,8 @@ function user_admin($callback_arg = '') {
   switch ($op) {
     case t('Create new account'):
     case 'create':
-      $build['user_register'] = drupal_get_form('user_register_form');
+      $build['user_register'] = entity_edit('user', NULL, 'register');
+      //drupal_get_form('user_register_form');
       break;
     default:
       if (!empty($_POST['accounts']) && isset($_POST['operation']) && ($_POST['operation'] == 'cancel')) {
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 865f17b..d19dee0 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -149,6 +149,10 @@ function user_entity_info() {
     'user' => array(
       'label' => t('User'),
       'controller class' => 'UserController',
+      'form controller class' => array(
+        'default' => '\\Drupal\\Module\\User\\ProfileFormController',
+        'register' => '\\Drupal\\Module\\User\\RegisterFormController',
+      ),
       'base table' => 'users',
       'uri callback' => 'user_uri',
       'label callback' => 'user_label',
@@ -1643,8 +1647,8 @@ function user_menu() {
 
   $items['user/register'] = array(
     'title' => 'Create new account',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('user_register_form'),
+    'page callback' => 'entity_edit',
+    'page arguments' => array('user', NULL, 'register'),
     'access callback' => 'user_register_access',
     'type' => MENU_LOCAL_TASK,
   );
@@ -1811,8 +1815,8 @@ function user_menu() {
 
   $items['user/%user/edit'] = array(
     'title' => 'Edit',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('user_profile_form', 1),
+    'page callback' => 'entity_edit',
+    'page arguments' => array('user', 1),
     'access callback' => 'user_edit_access',
     'access arguments' => array(1),
     'type' => MENU_LOCAL_TASK,
@@ -3717,21 +3721,10 @@ function user_register_form($form, &$form_state) {
     '#value' => t('Create new account'),
   );
 
-  $form['#validate'][] = 'user_register_validate';
-  // Add the final user registration form submit handler.
-  $form['#submit'][] = 'user_register_submit';
-
   return $form;
 }
 
 /**
- * Validation function for the user registration form.
- */
-function user_register_validate($form, &$form_state) {
-  entity_form_field_validate('user', $form, $form_state);
-}
-
-/**
  * Submit handler for the user registration form.
  *
  * This function is shared by the installation form and the normal registration form,
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index c54bd4c..39b1978 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -224,10 +224,7 @@ function user_profile_form($form, &$form_state, $account) {
   //   $form_state. Remove in Drupal 8.
   $form['#user'] = $account;
 
-
   user_account_form($form, $form_state);
-  // Attach field widgets.
-  field_attach_form('user', $account, $form, $form_state);
 
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
@@ -241,10 +238,6 @@ function user_profile_form($form, &$form_state, $account) {
     '#access' => $account->uid > 1 && (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')),
   );
 
-  $form['#validate'][] = 'user_profile_form_validate';
-  // Add the final user profile form submit handler.
-  $form['#submit'][] = 'user_profile_form_submit';
-
   return $form;
 }
 
