diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 035f282..dcae210 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -115,6 +115,9 @@ public function build(ContainerBuilder $container) {
     // Register the EntityManager.
     $container->register('plugin.manager.entity', 'Drupal\Core\Entity\EntityManager');
 
+    // Register the Entity WizardFormController.
+    $container->register('entity.wizard', 'Drupal\Core\Wizard\WizardFormController');
+
     // The 'request' scope and service enable services to depend on the Request
     // object and get reconstructed when the request object changes (e.g.,
     // during a subrequest).
diff --git a/core/lib/Drupal/Core/Wizard/WizardFormController.php b/core/lib/Drupal/Core/Wizard/WizardFormController.php
new file mode 100644
index 0000000..465df44
--- /dev/null
+++ b/core/lib/Drupal/Core/Wizard/WizardFormController.php
@@ -0,0 +1,235 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Wizard\WizardFormController.
+ */
+
+namespace Drupal\Core\Wizard;
+
+use Drupal\Core\Entity\EntityFormController;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\user\TempStoreFactory;
+
+/**
+ * Form controller for the Views edit form.
+ */
+class WizardFormController extends EntityFormController {
+
+  /**
+   * The entity type definition.
+   *
+   * @var array
+   */
+  protected $entityInfo;
+
+  /**
+   * The entity type definition key that will specify the relevant steps.
+   *
+   * Subclasses may change this to support multiple entity form wizards.
+   *
+   * @var string
+   */
+  protected $stepKey = 'steps';
+
+  /**
+   * The entity type definition key that will specify the relevant destination.
+   *
+   * Subclasses may change this to support multiple entity form wizards
+   * destinations.
+   *
+   * @var string
+   */
+  protected $destinationKey = 'destination';
+
+  /**
+   * Override \Drupal\Core\Entity\EntityFormController::__construct().
+   *
+   * Allow an operation to not be passed so that it can be setup in the
+   * create() method for routing purposes.
+   */
+  public function __construct($operation = NULL) {
+    if (!empty($operation)) {
+      $this->operation = $operation;
+    }
+  }
+
+  /**
+   * Provides a create utility for multi page entity wizard forms.
+   *
+   * @param string $entity_type
+   *   The type of entity we are working with. This will be used for
+   *   entity_create() calls as well as unique storage within tempstore.
+   * @param string $operation
+   *   The current step in the form wizard process.
+   * @param string $id
+   *   The unique identifier of the entity the form wizard is building.
+   * @param string $steps_key
+   *   The key that indicates which group of steps to pull back from the entity
+   *   definition.
+   *
+   * @return array
+   *   The renderable array from the current step of the entity's available form
+   *   controllers.
+   */
+  public function create($entity_type, $operation, $id = NULL, $steps_key = 'steps') {
+    $this->operation = $operation;
+    if (empty($id)) {
+      $entity = entity_create($entity_type, array());
+    }
+    else {
+      $entity = drupal_container()->get('user.tempstore')->get($entity_type)->get($id);
+      if (!$entity instanceof EntityInterface) {
+        $entity = entity_load($entity_type, $id);
+      }
+    }
+    $definition = $entity->entityInfo();
+    // This could be any entity form controller and is not necessarily documented
+    // in the steps. If it is not in the steps, it will not have a title.
+    if (isset($definition[$steps_key][$operation])) {
+      drupal_set_title($definition[$steps_key][$operation]);
+    }
+    return entity_get_form($entity, $operation);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::init().
+   */
+  protected function init(array &$form_state, EntityInterface $entity) {
+    parent::init($form_state, $entity);
+    $this->entityInfo = $entity->entityInfo();
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::actions().
+   *
+   * Digs through the entity definition's steps to determine if previous or
+   * next steps exist in order to display the appropriate buttons and text on
+   * those buttons.
+   */
+  protected function actions(array $form, array &$form_state) {
+    $actions = parent::actions($form, $form_state);
+    // Delete should not generally be accessible from a wizard. Set access
+    // to false so that others can easily re-enable if they want it.
+    if (isset($actions['delete'])) {
+      $actions['delete']['#access'] = FALSE;
+    }
+    $entity = $this->buildEntity($form, $form_state += array('values' => array()));
+    // Get the steps of the wizard from the entity definition.
+    $steps = array_keys($this->entityInfo[$this->stepKey]);
+    // Slice to find the operations that occur before the current operation.
+    $before = array_slice($this->entityInfo[$this->stepKey], 0, array_search($this->getOperation(), $steps));
+    // Slice to find the operations that occur after the current operation.
+    $after = array_slice($this->entityInfo[$this->stepKey], array_search($this->getOperation(), $steps) + 1);
+
+    // If there are steps after this one, label the button "Next" otherwise
+    // label it "Finish".
+    if ($after) {
+      $actions['submit']['#value'] = t('Next');
+    }
+    else {
+      $actions['submit']['#value'] = t('Finish');
+      $actions['submit']['#submit'][] = array($this, 'finish');
+    }
+
+    // If there are steps before this one, label the button "previous"
+    // otherwise do not display a button.
+    if ($before) {
+      $actions['previous'] = array(
+        '#value' => t('Previous'),
+        '#submit' => array(
+          array($this, 'previous'),
+        ),
+        '#limit_validation_errors' => array(),
+        '#weight' => -10,
+      );
+    }
+
+    return $actions;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::submit().
+   *
+   * Instead of saving the entity at each step, we populate a tempstore with
+   * the entity for the next step.
+   */
+  public function submit(array $form, array &$form_state) {
+    if ($form_state['values']['op'] == 'Next') {
+      $entity = $this->buildEntity($form, $form_state);
+      drupal_container()->get('user.tempstore')->get($entity->entityType())->set($entity->id(), $entity);
+      // Get the steps by key.
+      $steps = array_keys($this->entityInfo[$this->stepKey]);
+      // Get the steps after the current step.
+      $after = array_slice($this->entityInfo[$this->stepKey], array_search($this->getOperation(), $steps) + 1);
+      // Get the steps after the current step by key.
+      $after = array_keys($after);
+
+      $form_state['redirect'] = $this->redirect($entity, $after[0]);
+    }
+  }
+
+  /**
+   * Form submission handler for the 'previous' action.
+   *
+   * This method finds the previous step and redirects us to it.
+   *
+   * @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.
+   */
+  public function previous(array $form, array &$form_state) {
+    $entity = $this->buildEntity($form, $form_state);
+    // Get the steps by key.
+    $steps = array_keys($this->entityInfo[$this->stepKey]);
+    // Get the steps before the current step.
+    $before = array_slice($this->entityInfo[$this->stepKey], 0, array_search($this->getOperation(), $steps));
+    // Get the steps before the current step by key.
+    $before = array_keys($before);
+    // Reverse the steps for easy access to the next step.
+    $before = array_reverse($before);
+
+    $form_state['redirect'] = $this->redirect($entity, $before[0]);
+  }
+
+  /**
+   * Form submission handler for the 'previous' action.
+   *
+   * Retrieves the entity, saves it and deletes the values in the tempstore.
+   * This is handled as a separate method from submit() in order to keep the
+   * concerns of next() separate from finish(). There is no next() method
+   * because submit() will be fired in all forward moving steps. Submit just
+   * checks the operator to make sure that it is not firing on finish().
+   *
+   * @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.
+   */
+  public function finish(array $form, array &$form_state) {
+    $entity = parent::submit($form, $form_state);
+    $entity->save();
+    drupal_container()->get('user.tempstore')->get($entity->entityType())->delete($entity->id());
+    $form_state['redirect'] = $this->redirect($entity);
+  }
+
+  /**
+   * A simple method for managing the redirect url of each step.
+   *
+   * @param EntityInterface $entity
+   *   The entity being saved or updated.
+   * @param string $operation
+   *   A simple string representation of the current step and corresponding
+   *   form controller.
+   *
+   * @return string
+   *   A uri for to be placed in $form_state['redirect'].
+   */
+  public function redirect(EntityInterface $entity, $operation = NULL) {
+    if (!empty($operation)) {
+      return $this->entityInfo[$this->destinationKey] . '/' . $entity->id() . '/' . $operation;
+    }
+    return $this->entityInfo[$this->destinationKey];
+  }
+}
