diff --git a/core/modules/edit/edit.module b/core/modules/edit/edit.module
index a6ee046..f15e92b 100644
--- a/core/modules/edit/edit.module
+++ b/core/modules/edit/edit.module
@@ -96,7 +96,8 @@ function edit_library_info() {
       array(
         'data' => array('edit' => array(
           'metadataURL' => url('edit/metadata'),
-          'fieldFormURL' => url('edit/form/!entity_type/!id/!field_name/!langcode/!view_mode'),
+          'fieldFormURL' => url('edit/form/!entity_type/!id/!field_name/!langcode/!view_mode/!reset_tempstore'),
+          'entitySaveURL' => url('edit/entity/!entity_type/!id/!langcode'),
           'context' => 'body',
         )),
         'type' => 'setting',
diff --git a/core/modules/edit/edit.routing.yml b/core/modules/edit/edit.routing.yml
index d66881d..f962cf7 100644
--- a/core/modules/edit/edit.routing.yml
+++ b/core/modules/edit/edit.routing.yml
@@ -6,9 +6,18 @@ edit_metadata:
     _permission: 'access in-place editing'
 
 edit_field_form:
-  pattern: '/edit/form/{entity_type}/{entity}/{field_name}/{langcode}/{view_mode}'
+  pattern: '/edit/form/{entity_type}/{entity}/{field_name}/{langcode}/{view_mode}/{reset_tempstore}'
   defaults:
     _controller: '\Drupal\edit\EditController::fieldForm'
   requirements:
     _permission: 'access in-place editing'
     _access_edit_entity_field: 'TRUE'
+
+
+edit_entity_save:
+  pattern: '/edit/entity/{entity_type}/{entity}'
+  defaults:
+    _controller: '\Drupal\edit\EditController::entitySave'
+  requirements:
+    _permission: 'access in-place editing'
+    _access_edit_entity: 'TRUE'
diff --git a/core/modules/edit/edit.services.yml b/core/modules/edit/edit.services.yml
index 8f72c77..2290fd1 100644
--- a/core/modules/edit/edit.services.yml
+++ b/core/modules/edit/edit.services.yml
@@ -6,6 +6,10 @@ services:
     class: Drupal\edit\Access\EditEntityFieldAccessCheck
     tags:
       - { name: access_check }
+  access_check.edit.entity:
+    class: Drupal\edit\Access\EditEntityAccessCheck
+    tags:
+      - { name: access_check }
   edit.editor.selector:
     class: Drupal\edit\EditorSelector
     arguments: ['@plugin.manager.edit.editor']
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php
new file mode 100644
index 0000000..36c2254
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheck.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Access\EditEntityAccessCheck.
+ */
+
+namespace Drupal\edit\Access;
+
+use Drupal\Core\Access\AccessCheckInterface;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Access check for editing entities.
+ */
+class EditEntityAccessCheck implements AccessCheckInterface, EditEntityAccessCheckInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function applies(Route $route) {
+    // @see edit.routing.yml
+    return array_key_exists('_access_edit_entity', $route->getRequirements());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(Route $route, Request $request) {
+    // @todo Request argument validation and object loading should happen
+    //   elsewhere in the request processing pipeline:
+    //   http://drupal.org/node/1798214.
+    $this->validateAndUpcastRequestAttributes($request);
+
+    return $this->accessEditEntity($request->attributes->get('entity'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function accessEditEntity(EntityInterface $entity) {
+    $entity_type = $entity->entityType();
+    // @todo Generalize to all entity types once http://drupal.org/node/1862750
+    // is done.
+    return ($entity_type == 'node' && node_access('update', $entity));
+  }
+
+  /**
+   * Validates and upcasts request attributes.
+   */
+  protected function validateAndUpcastRequestAttributes(Request $request) {
+    // Load the entity.
+    if (!is_object($entity = $request->attributes->get('entity'))) {
+      $entity_id = $entity;
+      $entity_type = $request->attributes->get('entity_type');
+      if (!$entity_type || !entity_get_info($entity_type)) {
+        throw new NotFoundHttpException();
+      }
+      $entity = entity_load($entity_type, $entity_id);
+      if (!$entity) {
+        throw new NotFoundHttpException();
+      }
+      $request->attributes->set('entity', $entity);
+    }
+  }
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheckInterface.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheckInterface.php
new file mode 100644
index 0000000..5df39e1
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityAccessCheckInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Access\EditEntityAccessCheckInterface.
+ */
+
+namespace Drupal\edit\Access;
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Access check for editing entities.
+ */
+interface EditEntityAccessCheckInterface {
+
+  /**
+   * Checks access to edit the requested entity.
+   */
+  public function accessEditEntity(EntityInterface $entity);
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
index 9eac5bc..d95252a 100644
--- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
@@ -22,6 +22,7 @@ class EditEntityFieldAccessCheck implements AccessCheckInterface, EditEntityFiel
    * Implements AccessCheckInterface::applies().
    */
   public function applies(Route $route) {
+    // @see edit.routing.yml
     return array_key_exists('_access_edit_entity_field', $route->getRequirements());
   }
 
diff --git a/core/modules/edit/lib/Drupal/edit/Ajax/EntitySavedCommand.php b/core/modules/edit/lib/Drupal/edit/Ajax/EntitySavedCommand.php
new file mode 100644
index 0000000..6b6cc59
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Ajax/EntitySavedCommand.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Ajax\EntitySavedCommand.
+ */
+
+namespace Drupal\edit\Ajax;
+
+use Drupal\Core\Ajax\CommandInterface;
+
+/**
+ * AJAX command to indicate the entity was loaded from TempStore and saved into
+ * the database.
+ */
+class EntitySavedCommand extends BaseCommand {
+
+  /**
+   * Constructs a EntitySaveCommand object.
+   *
+   * @param string $data
+   *   The data to pass on to the client side.
+   */
+  public function __construct($data) {
+    parent::__construct('editEntitySaved', $data);
+  }
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/Ajax/FieldFormSavedCommand.php b/core/modules/edit/lib/Drupal/edit/Ajax/FieldFormSavedCommand.php
index d2a9630..96a1553 100644
--- a/core/modules/edit/lib/Drupal/edit/Ajax/FieldFormSavedCommand.php
+++ b/core/modules/edit/lib/Drupal/edit/Ajax/FieldFormSavedCommand.php
@@ -10,8 +10,8 @@
 use Drupal\Core\Ajax\CommandInterface;
 
 /**
- * AJAX command to indicate a field form was saved without validation errors and
- * pass the rerendered field to Edit's JavaScript app.
+ * AJAX command to indicate a field was saved into TempStore without validation
+ * errors and pass the rerendered field to Edit's JavaScript app.
  */
 class FieldFormSavedCommand extends BaseCommand {
 
diff --git a/core/modules/edit/lib/Drupal/edit/EditController.php b/core/modules/edit/lib/Drupal/edit/EditController.php
index a9b051b..57dd71b 100644
--- a/core/modules/edit/lib/Drupal/edit/EditController.php
+++ b/core/modules/edit/lib/Drupal/edit/EditController.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\edit;
 
+use Drupal;
 use Symfony\Component\DependencyInjection\ContainerAware;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
@@ -16,6 +17,7 @@
 use Drupal\edit\Ajax\FieldFormCommand;
 use Drupal\edit\Ajax\FieldFormSavedCommand;
 use Drupal\edit\Ajax\FieldFormValidationErrorsCommand;
+use Drupal\edit\Ajax\EntitySavedCommand;
 
 /**
  * Returns responses for Edit module routes.
@@ -69,6 +71,46 @@ public function metadata(Request $request) {
   /**
    * Returns a single field edit form as an Ajax response.
    *
+   * @todo When using entity toolbar/TempStore, this will have to handle
+   *   1) rendering form
+   *   2) validating form
+   *   3) rendering the modified field in its formatter.
+   *
+   * I don't remember if we'd said that validation should only occur when saving
+   * the entire entity, but AFAICT that's technically actually impossible:
+   * validation errors occur on the per-field level, and to be able to show each
+   * field's validation errors, we'd have to open up the "Create.js
+   * PropertyEditor widgets" ("in-place editors" if you will) for each field,
+   * and show the validation errors within that for each field. Imagine a image,
+   * taxonomy, file, entity reference, etc. field, all being opened up at the
+   * same time. That will be a disastrous UI. We could potentially make it work
+   * to just have all field validation errors at the top (in the entity toolbar?)
+   * like for a regular form validation, but then the user would still have to
+   * click into each invalid field (which would likely have red outlines) to
+   * open its Create.js PropertyEditor widget to be able to enter a valid value.
+   * That would require big changes in the JS, PHP and overall UI, so I think it
+   * would be better to defer that to a second iteration. If we can make it work
+   * this way, that will probably be easier.
+   *
+   * Another technical aspect that we haven't addressed yet is the session
+   * aspect. We don't support starting to edit an entity via in-place editing
+   * (and having it live in TempStore) today, then browsing away and then start
+   * in-place editing it again tomorrow and having that continue where you left
+   * off.
+   * So: how to determine when to *clear* the existing data in TempStore?
+   *
+   * Finally, the tricky bit here is that (AFAICT, see above) we want validation
+   * but not submission. So… we want to trigger the "save" process, without
+   * actually saving. This can be pretty easy, or insanely hard. Especially
+   * because we DON'T want "entity (pre)save" or "field (pre)save" hooks to be
+   * fired… (that should only happen in entitySave() below).
+   *
+   * And after all of the above, there's sun's big comment at
+   * http://drupal.org/node/1510544#comment-6988746 (#130) which argues that
+   * using the TempStore for content entities is a bad idea in general, that we
+   * should use revisions for this. Also definitely see comments #140, #141 and
+   * #151.
+   *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity being edited.
    * @param string $field_name
@@ -77,12 +119,24 @@ public function metadata(Request $request) {
    *   The name of the language for which the field is being edited.
    * @param string $view_mode
    *   The view mode the field should be rerendered in.
+   * @param bool $reset_tempstore
+   *   Set to FALSE if the existing tempstore version should be kept, or TRUE
+   *   if the existing tempstore version should be removed.
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   The Ajax response.
    */
-  public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view_mode) {
+  public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view_mode, $reset_tempstore = FALSE) {
     $response = new AjaxResponse();
 
+    // Replace entity with tempstore copy if available, init tempstore copy
+    // otherwise.
+    if (!$reset_tempstore && ($temp_entity = Drupal::service('user.tempstore')->get('edit')->get($entity->uuid))) {
+      $entity = $temp_entity;
+    }
+    else {
+      Drupal::service('user.tempstore')->get('edit')->set($entity->uuid, $entity);
+    }
+
     $form_state = array(
       'langcode' => $langcode,
       'no_redirect' => TRUE,
@@ -91,9 +145,9 @@ public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view
     $form = drupal_build_form('edit_field_form', $form_state);
 
     if (!empty($form_state['executed'])) {
-      // The form submission took care of saving the updated entity. Return the
-      // updated view of the field.
-      $entity = entity_load($form_state['entity']->entityType(), $form_state['entity']->id(), TRUE);
+      // The form submission saved the entity in tempstore. Return the
+      // updated view of the field from the tempstore copy.
+      $entity = Drupal::service('user.tempstore')->get('edit')->get($entity->uuid);
       $output = field_view_field($entity, $field_name, $view_mode, $langcode);
 
       $response->addCommand(new FieldFormSavedCommand(drupal_render($output)));
@@ -116,4 +170,49 @@ public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view
     return $response;
   }
 
+  /**
+   * Saves an entity into the database, from TempStore.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being edited.
+   *
+   * @todo All fields should already be valid, and the currently rendered
+   * representation on the client side should already be up to date. Both thanks
+   * to fieldForm() above. So, this hook should really do:
+   *  - take the entity from TempStore and save it into the database
+   *  - ensure the relevant "entity/field (pre)save" hooks are fired
+   *  - remove the entity from TempStore upon success
+   *
+   * Question is whether we can really assume there will be no validation
+   * errors? Can *nothing* go wrong?
+   *
+   * If you were to follow the approach I outlined (and it would be possible to
+   * make it work this way), then:
+   * - in-place editing should continue to work as it does today, with the
+   *   current UI
+   * - BUT even though the changes would be immediately visible, as if they were
+   *   being saved like they are today, they would really just live in tempstore
+   * - Doing a GET request to edit/entity/<entity type>/<entity ID>
+   *   would cause it to really be saved into the DB. Just using the browser
+   *   should be fine; you don't have to do it via AJAX.
+   *
+   * This means you *should* be able to not change a line of JavaScript — if I
+   * made no mistakes :)
+   */
+  public function entitySave(EntityInterface $entity) {
+    // Take the entity from tempstore and save in entity storage. fieldForm()
+    // ensures that the tempstore copy exists ahead.
+    $tempstore = Drupal::service('user.tempstore')->get('edit');
+    $tempstore->get($entity->uuid)->save();
+    $tempstore->delete($entity->uuid);
+
+    // @todo add response that makes sense.
+    $output = array();
+
+    // Respond to client that the entity was saved properly.
+    $response = new AjaxResponse();
+    $response->addCommand(new EntitySavedCommand($output));
+    return $response;
+  }
+
 }
diff --git a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
index 1959ae7..2f89043 100644
--- a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
+++ b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\edit\Form;
 
+use Drupal;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -71,7 +72,9 @@ public function validate(array $form, array &$form_state) {
    */
   public function submit(array $form, array &$form_state) {
     $form_state['entity'] = $this->buildEntity($form, $form_state);
-    $form_state['entity']->save();
+
+    // Store entity in tempstore with its UUID as tempstore key.
+    Drupal::service('user.tempstore')->get('edit')->set($form_state['entity']->uuid, $form_state['entity']);
   }
 
   /**
