diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDeleteFormBase.php b/core/lib/Drupal/Core/Entity/ContentEntityDeleteFormBase.php
new file mode 100644
index 0000000..794b792
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/ContentEntityDeleteFormBase.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\ContentEntityDeleteFormBase.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a generic base class for a content entity deletion form.
+ */
+abstract class ContentEntityDeleteFormBase extends ContentEntityConfirmFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $this->entity->delete();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityDeleteFormBase.php b/core/lib/Drupal/Core/Entity/EntityDeleteFormBase.php
new file mode 100644
index 0000000..0789a25
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityDeleteFormBase.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\EntityConfirmFormBase.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a generic base class for an entity deletion form.
+ *
+ * @ingroup entity_api
+ */
+abstract class EntityDeleteFormBase extends EntityConfirmFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $this->entity->delete();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index f154844..f013e41 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -281,7 +281,7 @@ public function submit(array $form, FormStateInterface $form_state) {
    *   The current state of the form.
    */
   public function save(array $form, FormStateInterface $form_state) {
-    // @todo Perform common save operations.
+    $this->entity->save();
   }
 
   /**
diff --git a/core/modules/action/src/ActionFormBase.php b/core/modules/action/src/ActionFormBase.php
index 88e78ad..b6648bc 100644
--- a/core/modules/action/src/ActionFormBase.php
+++ b/core/modules/action/src/ActionFormBase.php
@@ -147,7 +147,7 @@ public function submit(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $this->entity->save();
+    parent::save($form, $form_state);
     drupal_set_message($this->t('The action has been successfully saved.'));
 
     $form_state->setRedirect('action.admin');
diff --git a/core/modules/action/src/Form/ActionDeleteForm.php b/core/modules/action/src/Form/ActionDeleteForm.php
index 0f89e3d..da7f847 100644
--- a/core/modules/action/src/Form/ActionDeleteForm.php
+++ b/core/modules/action/src/Form/ActionDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\action\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Builds a form to delete an action.
  */
-class ActionDeleteForm extends EntityConfirmFormBase {
+class ActionDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,8 +40,8 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     $this->logger('user')->notice('Deleted action %aid (%action)', array('%aid' => $this->entity->id(), '%action' => $this->entity->label()));
     drupal_set_message($this->t('Action %action was deleted', array('%action' => $this->entity->label())));
diff --git a/core/modules/aggregator/src/FeedForm.php b/core/modules/aggregator/src/FeedForm.php
index 1832cb5..228cd53 100644
--- a/core/modules/aggregator/src/FeedForm.php
+++ b/core/modules/aggregator/src/FeedForm.php
@@ -64,7 +64,10 @@ public function validate(array $form, FormStateInterface $form_state) {
   public function save(array $form, FormStateInterface $form_state) {
     $feed = $this->entity;
     $insert = (bool) $feed->id();
-    $feed->save();
+
+    parent::save($form, $form_state);
+
+    // @ŧodo Split this into dedicated add and edit forms.
     if ($insert) {
       drupal_set_message($this->t('The feed %feed has been updated.', array('%feed' => $feed->label())));
       $form_state->setRedirectUrl($feed->urlInfo('canonical'));
diff --git a/core/modules/aggregator/src/Form/FeedDeleteForm.php b/core/modules/aggregator/src/Form/FeedDeleteForm.php
index eba206b..737e49f 100644
--- a/core/modules/aggregator/src/Form/FeedDeleteForm.php
+++ b/core/modules/aggregator/src/Form/FeedDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\aggregator\Form;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a form for deleting a feed.
  */
-class FeedDeleteForm extends ContentEntityConfirmFormBase {
+class FeedDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,8 +40,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+    
     $this->logger('aggregator')->notice('Feed %feed deleted.', array('%feed' => $this->entity->label()));
     drupal_set_message($this->t('The feed %feed has been deleted.', array('%feed' => $this->entity->label())));
     $form_state->setRedirect('aggregator.sources');
diff --git a/core/modules/block/src/BlockForm.php b/core/modules/block/src/BlockForm.php
index e289086..d6eb8bb 100644
--- a/core/modules/block/src/BlockForm.php
+++ b/core/modules/block/src/BlockForm.php
@@ -176,9 +176,13 @@ public function submit(array $form, FormStateInterface $form_state) {
     $entity->getPlugin()->submitConfigurationForm($form, $settings);
     // Update the original form values.
     $form_state->setValue('settings', $settings['values']);
+  }
 
-    // Save the settings of the plugin.
-    $entity->save();
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     drupal_set_message($this->t('The block configuration has been saved.'));
     $form_state->setRedirect(
diff --git a/core/modules/block/src/Form/BlockDeleteForm.php b/core/modules/block/src/Form/BlockDeleteForm.php
index 1567875..ed110f1 100644
--- a/core/modules/block/src/Form/BlockDeleteForm.php
+++ b/core/modules/block/src/Form/BlockDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\block\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a deletion confirmation form for the block instance deletion form.
  */
-class BlockDeleteForm extends EntityConfirmFormBase {
+class BlockDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,8 +40,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('The block %name has been removed.', array('%name' => $this->entity->label())));
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
diff --git a/core/modules/block_content/src/Controller/BlockContentController.php b/core/modules/block_content/src/Controller/BlockContentController.php
index 4716bba..7758180 100644
--- a/core/modules/block_content/src/Controller/BlockContentController.php
+++ b/core/modules/block_content/src/Controller/BlockContentController.php
@@ -96,7 +96,7 @@ public function addForm(BlockContentTypeInterface $block_content_type, Request $
       // newly created block in the given theme.
       $block->setTheme($theme);
     }
-    return $this->entityFormBuilder()->getForm($block);
+    return $this->entityFormBuilder()->getForm($block, 'add');
   }
 
   /**
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index c06d4e8..7745385 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -26,10 +26,9 @@
  *     "list_builder" = "Drupal\block_content\BlockContentListBuilder",
  *     "view_builder" = "Drupal\block_content\BlockContentViewBuilder",
  *     "form" = {
- *       "add" = "Drupal\block_content\BlockContentForm",
- *       "edit" = "Drupal\block_content\BlockContentForm",
+ *       "add" = "Drupal\block_content\Form\BlockContentAddForm",
+ *       "edit" = "Drupal\block_content\Form\BlockContentEditForm",
  *       "delete" = "Drupal\block_content\Form\BlockContentDeleteForm",
- *       "default" = "Drupal\block_content\BlockContentForm"
  *     },
  *     "translation" = "Drupal\block_content\BlockContentTranslationHandler"
  *   },
diff --git a/core/modules/block_content/src/Entity/BlockContentType.php b/core/modules/block_content/src/Entity/BlockContentType.php
index 4304b6d..7bdd9c2 100644
--- a/core/modules/block_content/src/Entity/BlockContentType.php
+++ b/core/modules/block_content/src/Entity/BlockContentType.php
@@ -20,9 +20,8 @@
  *   label = @Translation("Custom block type"),
  *   controllers = {
  *     "form" = {
- *       "default" = "Drupal\block_content\BlockContentTypeForm",
- *       "add" = "Drupal\block_content\BlockContentTypeForm",
- *       "edit" = "Drupal\block_content\BlockContentTypeForm",
+ *       "add" = "Drupal\block_content\Form\BlockContentTypeAddForm",
+ *       "edit" = "Drupal\block_content\Form\BlockContentTypeEditForm",
  *       "delete" = "Drupal\block_content\Form\BlockContentTypeDeleteForm"
  *     },
  *     "list_builder" = "Drupal\block_content\BlockContentTypeListBuilder"
diff --git a/core/modules/block_content/src/Form/BlockContentAddForm.php b/core/modules/block_content/src/Form/BlockContentAddForm.php
new file mode 100644
index 0000000..e966262
--- /dev/null
+++ b/core/modules/block_content/src/Form/BlockContentAddForm.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_content\Form\BlockContentAddForm.
+ */
+
+namespace Drupal\block_content\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding custom blocks.
+ */
+class BlockContentAddForm extends BlockContentFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block = $this->entity;
+    $block_type = entity_load('block_content_type', $block->bundle());
+
+    $t_args = array('@type' => $block_type->label(), '%info' => $block->label());
+    $log_context = array('@type' => $block->bundle(), '%info' => $block->label());
+
+    drupal_set_message($this->t('@type %info has been created.', $t_args));
+    $this->logger('block_content')->notice('@type: added %info.', $log_context);
+
+    if (!$theme = $block->getTheme()) {
+      $theme = $this->config('system.theme')->get('default');
+    }
+    $form_state->setRedirect(
+      'block.admin_add',
+      array(
+        'plugin_id' => 'block_content:' . $block->uuid(),
+        'theme' => $theme,
+      )
+    );
+  }
+
+}
diff --git a/core/modules/block_content/src/Form/BlockContentDeleteForm.php b/core/modules/block_content/src/Form/BlockContentDeleteForm.php
index d376ec1..c5fd9a5 100644
--- a/core/modules/block_content/src/Form/BlockContentDeleteForm.php
+++ b/core/modules/block_content/src/Form/BlockContentDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\block_content\Form;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a confirmation form for deleting a custom block entity.
  */
-class BlockContentDeleteForm extends ContentEntityConfirmFormBase {
+class BlockContentDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -54,8 +54,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('Custom block %label has been deleted.', array('%label' => $this->entity->label())));
     $this->logger('block_content')->notice('Custom block %label has been deleted.', array('%label' => $this->entity->label()));
     $form_state->setRedirect('block_content.list');
diff --git a/core/modules/block_content/src/Form/BlockContentEditForm.php b/core/modules/block_content/src/Form/BlockContentEditForm.php
new file mode 100644
index 0000000..7b47542
--- /dev/null
+++ b/core/modules/block_content/src/Form/BlockContentEditForm.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_content\Form\BlockContentEditForm.
+ */
+
+namespace Drupal\block_content\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for editing custom blocks.
+ */
+class BlockContentEditForm extends BlockContentFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block = $this->entity;
+    $block_type = entity_load('block_content_type', $block->bundle());
+
+    $t_args = array('@type' => $block_type->label(), '%info' => $block->label());
+    $log_context = array('@type' => $block->bundle(), '%info' => $block->label());
+
+    drupal_set_message($this->t('@type %info has been updated.', $t_args));
+    $this->logger('block_content')->notice('@type: updated %info.', $log_context);
+
+    $form_state->setRedirect('block_content.list');
+  }
+
+}
diff --git a/core/modules/block_content/src/BlockContentForm.php b/core/modules/block_content/src/Form/BlockContentFormBase.php
similarity index 84%
rename from core/modules/block_content/src/BlockContentForm.php
rename to core/modules/block_content/src/Form/BlockContentFormBase.php
index cd2b951..6b0b1c7 100644
--- a/core/modules/block_content/src/BlockContentForm.php
+++ b/core/modules/block_content/src/Form/BlockContentFormBase.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\block_content\BlockContentForm.
+ * Contains \Drupal\block_content\Form\BlockContentFormBase.
  */
 
-namespace Drupal\block_content;
+namespace Drupal\block_content\Form;
 
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -16,9 +16,9 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Form controller for the custom block edit forms.
+ * Provides a common base form for custom blocks.
  */
-class BlockContentForm extends ContentEntityForm {
+abstract class BlockContentFormBase extends ContentEntityForm {
 
   /**
    * The custom block storage.
@@ -35,7 +35,7 @@ class BlockContentForm extends ContentEntityForm {
   protected $languageManager;
 
   /**
-   * Constructs a BlockContentForm object.
+   * Constructs a BlockContentFormBase object.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
@@ -191,41 +191,13 @@ public function submit(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $block = $this->entity;
-    $insert = $block->isNew();
-    $block->save();
-    $context = array('@type' => $block->bundle(), '%info' => $block->label());
-    $logger = $this->logger('block_content');
-    $block_type = entity_load('block_content_type', $block->bundle());
-    $t_args = array('@type' => $block_type->label(), '%info' => $block->label());
+    parent::save($form, $form_state);
 
-    if ($insert) {
-      $logger->notice('@type: added %info.', $context);
-      drupal_set_message($this->t('@type %info has been created.', $t_args));
-    }
-    else {
-      $logger->notice('@type: updated %info.', $context);
-      drupal_set_message($this->t('@type %info has been updated.', $t_args));
-    }
+    $block = $this->entity;
 
     if ($block->id()) {
       $form_state->setValue('id', $block->id());
       $form_state['id'] = $block->id();
-      if ($insert) {
-        if (!$theme = $block->getTheme()) {
-          $theme = $this->config('system.theme')->get('default');
-        }
-        $form_state->setRedirect(
-          'block.admin_add',
-          array(
-            'plugin_id' => 'block_content:' . $block->uuid(),
-            'theme' => $theme,
-          )
-        );
-      }
-      else {
-        $form_state->setRedirect('block_content.list');
-      }
     }
     else {
       // In the unlikely case something went wrong on save, the block will be
diff --git a/core/modules/block_content/src/Form/BlockContentTypeAddForm.php b/core/modules/block_content/src/Form/BlockContentTypeAddForm.php
new file mode 100644
index 0000000..e6f327c
--- /dev/null
+++ b/core/modules/block_content/src/Form/BlockContentTypeAddForm.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_content\Form\BlockContentTypeAddForm.
+ */
+
+namespace Drupal\block_content\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding block content types.
+ */
+class BlockContentTypeAddForm extends BlockContentTypeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block_type = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Custom block type %label has been added.', array('%label' => $block_type->label())));
+    $this->logger('block_content')->notice('Custom block type %label has been added.', array(
+      '%label' => $block_type->label(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php b/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php
index a1b9e9b..f47e725 100644
--- a/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php
+++ b/core/modules/block_content/src/Form/BlockContentTypeDeleteForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\block_content\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Entity\Query\QueryFactory;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
@@ -16,7 +16,7 @@
 /**
  * Provides a confirmation form for deleting a custom block type entity.
  */
-class BlockContentTypeDeleteForm extends EntityConfirmFormBase {
+class BlockContentTypeDeleteForm extends EntityDeleteFormBase {
 
   /**
    * The query factory to create entity queries.
@@ -83,8 +83,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message(t('Custom block type %label has been deleted.', array('%label' => $this->entity->label())));
     $this->logger('block_content')->notice('Custom block type %label has been deleted.', array('%label' => $this->entity->label()));
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/block_content/src/Form/BlockContentTypeEditForm.php b/core/modules/block_content/src/Form/BlockContentTypeEditForm.php
new file mode 100644
index 0000000..f3e2d34
--- /dev/null
+++ b/core/modules/block_content/src/Form/BlockContentTypeEditForm.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_content\Form\BlockContentTypeEditForm.
+ */
+
+namespace Drupal\block_content\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding block content types.
+ */
+class BlockContentTypeEditForm extends BlockContentTypeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block_type = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Custom block type %label has been updated.', array('%label' => $block_type->label())));
+    $this->logger('block_content')->notice('Custom block type %label has been updated.', array(
+      '%label' => $block_type->label(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/block_content/src/BlockContentTypeForm.php b/core/modules/block_content/src/Form/BlockContentTypeFormBase.php
similarity index 73%
rename from core/modules/block_content/src/BlockContentTypeForm.php
rename to core/modules/block_content/src/Form/BlockContentTypeFormBase.php
index 0675657..f218d87 100644
--- a/core/modules/block_content/src/BlockContentTypeForm.php
+++ b/core/modules/block_content/src/Form/BlockContentTypeFormBase.php
@@ -2,19 +2,19 @@
 
 /**
  * @file
- * Contains \Drupal\block_content\BlockContentTypeForm.
+ * Contains \Drupal\block_content\Form\BlockContentTypeFormBase.
  */
 
-namespace Drupal\block_content;
+namespace Drupal\block_content\Form;
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
- * Base form for category edit forms.
+ * Provides a common base form for block content type forms.
  */
-class BlockContentTypeForm extends EntityForm {
+abstract class BlockContentTypeFormBase extends EntityForm {
 
   /**
    * {@inheritdoc}
@@ -89,19 +89,7 @@ public function form(array $form, FormStateInterface $form_state) {
    * Overrides \Drupal\Core\Entity\EntityForm::save().
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $block_type = $this->entity;
-    $status = $block_type->save();
-
-    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
-    $logger = $this->logger('block_content');
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message(t('Custom block type %label has been updated.', array('%label' => $block_type->label())));
-      $logger->notice('Custom block type %label has been updated.', array('%label' => $block_type->label(), 'link' => $edit_link));
-    }
-    else {
-      drupal_set_message(t('Custom block type %label has been added.', array('%label' => $block_type->label())));
-      $logger->notice('Custom block type %label has been added.', array('%label' => $block_type->label(), 'link' => $edit_link));
-    }
+    parent::save($form, $form_state);
 
     $form_state->setRedirect('block_content.type_list');
   }
diff --git a/core/modules/book/src/Form/BookOutlineForm.php b/core/modules/book/src/Form/BookOutlineForm.php
index 93140dd..d024bd7 100644
--- a/core/modules/book/src/Form/BookOutlineForm.php
+++ b/core/modules/book/src/Form/BookOutlineForm.php
@@ -131,6 +131,13 @@ public function submit(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
+  public function save(array $form, FormStateInterface $form_state) {
+    // Unlike the parent function, do not actually save the entity.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function delete(array $form, FormStateInterface $form_state) {
     $form_state->setRedirectUrl($this->entity->urlInfo('book-remove-form'));
   }
diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml
index f7bae41..2255d7c 100644
--- a/core/modules/comment/comment.routing.yml
+++ b/core/modules/comment/comment.routing.yml
@@ -20,7 +20,7 @@ entity.comment.edit_form:
   path: '/comment/{comment}/edit'
   defaults:
     _title: 'Edit'
-    _entity_form: 'comment.default'
+    _entity_form: 'comment.edit'
   requirements:
     _entity_access: 'comment.update'
 
diff --git a/core/modules/comment/src/CommentPostRenderCache.php b/core/modules/comment/src/CommentPostRenderCache.php
index 24db82d..e3c1b22 100644
--- a/core/modules/comment/src/CommentPostRenderCache.php
+++ b/core/modules/comment/src/CommentPostRenderCache.php
@@ -69,7 +69,7 @@ public function renderForm(array $element, array $context) {
       'pid' => NULL,
     );
     $comment = $this->entityManager->getStorage('comment')->create($values);
-    $form = $this->entityFormBuilder->getForm($comment);
+    $form = $this->entityFormBuilder->getForm($comment, 'add');
     // @todo: This only works as long as assets are still tracked in a global
     //   static variable, see https://drupal.org/node/2238835
     $markup = drupal_render($form, TRUE);
diff --git a/core/modules/comment/src/Controller/CommentController.php b/core/modules/comment/src/Controller/CommentController.php
index e550afc..5bc43a7 100644
--- a/core/modules/comment/src/Controller/CommentController.php
+++ b/core/modules/comment/src/Controller/CommentController.php
@@ -257,7 +257,7 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_
       'entity_type' => $entity->getEntityTypeId(),
       'field_name' => $field_name,
     ));
-    $build['comment_form'] = $this->entityFormBuilder()->getForm($comment);
+    $build['comment_form'] = $this->entityFormBuilder()->getForm($comment, 'add');
 
     return $build;
   }
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index 8efdb4d..6639a29 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -28,7 +28,8 @@
  *     "access" = "Drupal\comment\CommentAccessControlHandler",
  *     "view_builder" = "Drupal\comment\CommentViewBuilder",
  *     "form" = {
- *       "default" = "Drupal\comment\CommentForm",
+ *       "add" = "Drupal\comment\Form\CommentAddForm",
+ *       "edit" = "Drupal\comment\Form\CommentEditForm",
  *       "delete" = "Drupal\comment\Form\DeleteForm"
  *     },
  *     "translation" = "Drupal\comment\CommentTranslationHandler"
diff --git a/core/modules/comment/src/Entity/CommentType.php b/core/modules/comment/src/Entity/CommentType.php
index 5edc24d..ce8fe5d 100644
--- a/core/modules/comment/src/Entity/CommentType.php
+++ b/core/modules/comment/src/Entity/CommentType.php
@@ -19,9 +19,8 @@
  *   label = @Translation("Comment type"),
  *   controllers = {
  *     "form" = {
- *       "default" = "Drupal\comment\CommentTypeForm",
- *       "add" = "Drupal\comment\CommentTypeForm",
- *       "edit" = "Drupal\comment\CommentTypeForm",
+ *       "add" = "Drupal\comment\Form\CommentTypeAddForm",
+ *       "edit" = "Drupal\comment\Form\CommentTypeEditForm",
  *       "delete" = "Drupal\comment\Form\CommentTypeDeleteForm"
  *     },
  *     "list_builder" = "Drupal\comment\CommentTypeListBuilder"
diff --git a/core/modules/comment/src/Form/CommentAddForm.php b/core/modules/comment/src/Form/CommentAddForm.php
new file mode 100644
index 0000000..8a65645
--- /dev/null
+++ b/core/modules/comment/src/Form/CommentAddForm.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\comment\Form\CommentAddForm.
+ */
+
+namespace Drupal\comment\Form;
+
+/**
+ * Provides a form for adding comments.
+ */
+class CommentAddForm extends CommentFormBase {
+}
diff --git a/core/modules/comment/src/Form/CommentEditForm.php b/core/modules/comment/src/Form/CommentEditForm.php
new file mode 100644
index 0000000..bdec0d1
--- /dev/null
+++ b/core/modules/comment/src/Form/CommentEditForm.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\comment\Form\CommentEditForm.
+ */
+
+namespace Drupal\comment\Form;
+
+/**
+ * Provides a form for editing comments.
+ */
+class CommentEditForm extends CommentFormBase {
+}
diff --git a/core/modules/comment/src/CommentForm.php b/core/modules/comment/src/Form/CommentFormBase.php
similarity index 98%
rename from core/modules/comment/src/CommentForm.php
rename to core/modules/comment/src/Form/CommentFormBase.php
index 3ba804d..f0636a8 100644
--- a/core/modules/comment/src/CommentForm.php
+++ b/core/modules/comment/src/Form/CommentFormBase.php
@@ -2,11 +2,12 @@
 
 /**
  * @file
- * Definition of Drupal\comment\CommentForm.
+ * Definition of Drupal\comment\Form\CommentFormBase.
  */
 
-namespace Drupal\comment;
+namespace Drupal\comment\Form;
 
+use Drupal\comment\CommentInterface;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
@@ -20,9 +21,9 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Base for controller for comment forms.
+ * Provides a base form for comment forms.
  */
-class CommentForm extends ContentEntityForm {
+abstract class CommentFormBase extends ContentEntityForm {
 
   /**
    * The current user.
@@ -42,7 +43,7 @@ public static function create(ContainerInterface $container) {
   }
 
   /**
-   * Constructs a new CommentForm.
+   * Constructs a new CommentFormBase.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager service.
diff --git a/core/modules/comment/src/Form/CommentTypeAddForm.php b/core/modules/comment/src/Form/CommentTypeAddForm.php
new file mode 100644
index 0000000..d9b589f
--- /dev/null
+++ b/core/modules/comment/src/Form/CommentTypeAddForm.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Form\CommentTypeAddForm.
+ */
+
+namespace Drupal\comment\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding comment types.
+ */
+class CommentTypeAddForm extends CommentTypeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block_type = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Comment type %label has been added.', array('%label' => $block_type->label())));
+    $this->logger->notice('Comment type %label has been added.', array(
+      '%label' => $block_type->label(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/comment/src/Form/CommentTypeDeleteForm.php b/core/modules/comment/src/Form/CommentTypeDeleteForm.php
index 043aac4..d25b95f 100644
--- a/core/modules/comment/src/Form/CommentTypeDeleteForm.php
+++ b/core/modules/comment/src/Form/CommentTypeDeleteForm.php
@@ -8,7 +8,7 @@
 namespace Drupal\comment\Form;
 
 use Drupal\comment\CommentManagerInterface;
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Entity\EntityManager;
 use Drupal\Core\Entity\Query\QueryFactory;
 use Drupal\Core\Form\FormStateInterface;
@@ -20,7 +20,7 @@
 /**
  * Provides a confirmation form for deleting a comment type entity.
  */
-class CommentTypeDeleteForm extends EntityConfirmFormBase {
+class CommentTypeDeleteForm extends EntityDeleteFormBase {
 
   /**
    * The query factory to create entity queries.
@@ -141,8 +141,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $form_state->setRedirect('comment.type_list');
     drupal_set_message($this->t('Comment type %label has been deleted.', array('%label' => $this->entity->label())));
     $this->logger->notice('comment type %label has been deleted.', array('%label' => $this->entity->label()));
diff --git a/core/modules/comment/src/Form/CommentTypeEditForm.php b/core/modules/comment/src/Form/CommentTypeEditForm.php
new file mode 100644
index 0000000..317bde2
--- /dev/null
+++ b/core/modules/comment/src/Form/CommentTypeEditForm.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\comment\Form\CommentTypeEditForm.
+ */
+
+namespace Drupal\comment\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding comment types.
+ */
+class CommentTypeEditForm extends CommentTypeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block_type = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Comment type %label has been updated.', array('%label' => $block_type->label())));
+    $this->logger->notice('Comment type %label has been updated.', array(
+      '%label' => $block_type->label(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/comment/src/CommentTypeForm.php b/core/modules/comment/src/Form/CommentTypeFormBase.php
similarity index 80%
rename from core/modules/comment/src/CommentTypeForm.php
rename to core/modules/comment/src/Form/CommentTypeFormBase.php
index 418aea1..74912ad 100644
--- a/core/modules/comment/src/CommentTypeForm.php
+++ b/core/modules/comment/src/Form/CommentTypeFormBase.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\comment\CommentTypeForm.
+ * Contains \Drupal\comment\Form\CommentTypeFormBase.
  */
 
-namespace Drupal\comment;
+namespace Drupal\comment\Form;
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -15,9 +15,9 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Base form controller for category edit forms.
+ * Provides a common base form for comment type forms.
  */
-class CommentTypeForm extends EntityForm {
+abstract class CommentTypeFormBase extends EntityForm {
 
   /**
    * Entity manager service.
@@ -134,18 +134,7 @@ public function form(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $comment_type = $this->entity;
-    $status = $comment_type->save();
-
-    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message(t('Comment type %label has been updated.', array('%label' => $comment_type->label())));
-      $this->logger->notice('Comment type %label has been updated.', array('%label' => $comment_type->label(), 'link' => $edit_link));
-    }
-    else {
-      drupal_set_message(t('Comment type %label has been added.', array('%label' => $comment_type->label())));
-      $this->logger->notice('Comment type %label has been added.', array('%label' => $comment_type->label(), 'link' =>  $edit_link));
-    }
+    parent::save($form, $form_state);
 
     $form_state->setRedirect('comment.type_list');
   }
diff --git a/core/modules/comment/src/Form/DeleteForm.php b/core/modules/comment/src/Form/DeleteForm.php
index 1340f28..17443af 100644
--- a/core/modules/comment/src/Form/DeleteForm.php
+++ b/core/modules/comment/src/Form/DeleteForm.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\comment\Form;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides the comment delete confirmation form.
  */
-class DeleteForm extends ContentEntityConfirmFormBase {
+class DeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -47,9 +47,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    // Delete the comment and its replies.
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('The comment and all its replies have been deleted.'));
     $this->logger('content')->notice('Deleted comment @cid and its replies.', array('@cid' => $this->entity->id()));
 
diff --git a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
index e5ad723..7d07a18 100644
--- a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
+++ b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php
@@ -195,7 +195,7 @@ public function viewElements(FieldItemListInterface $items) {
               'comment_type' => $this->getFieldSetting('comment_type'),
               'pid' => NULL,
             ));
-            $output['comment_form'] = $this->entityFormBuilder->getForm($comment);
+            $output['comment_form'] = $this->entityFormBuilder->getForm($comment, 'add');
           }
           // All other users need a user-specific form, which would break the
           // render cache: hence use a #post_render_cache callback.
diff --git a/core/modules/config/tests/config_test/config_test.routing.yml b/core/modules/config/tests/config_test/config_test.routing.yml
index 4873d20..024930f 100644
--- a/core/modules/config/tests/config_test/config_test.routing.yml
+++ b/core/modules/config/tests/config_test/config_test.routing.yml
@@ -9,14 +9,14 @@ config_test.list_page:
 config_test.entity_add:
   path: '/admin/structure/config_test/add'
   defaults:
-    _entity_form: 'config_test'
+    _entity_form: 'config_test.add'
   requirements:
     _access: 'TRUE'
 
 entity.config_test.edit_form:
   path: '/admin/structure/config_test/manage/{config_test}'
   defaults:
-    _entity_form: config_test
+    _entity_form: 'config_test.edit'
     _title_callback: '\Drupal\config_test\ConfigTestController::editTitle'
   requirements:
     _access: 'TRUE'
diff --git a/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php b/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php
index c314fc6..a3447fb 100644
--- a/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php
+++ b/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php
@@ -16,9 +16,6 @@
  *   controllers = {
  *     "storage" = "Drupal\config_test\ConfigTestStorage",
  *     "list_builder" = "Drupal\Core\Config\Entity\ConfigEntityListBuilder",
- *     "form" = {
- *       "default" = "Drupal\config_test\ConfigTestForm"
- *     }
  *   },
  *   config_prefix = "query",
  *   entity_keys = {
diff --git a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
index 36f7a69..353fba4 100644
--- a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
+++ b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
@@ -22,7 +22,8 @@
  *     "storage" = "Drupal\config_test\ConfigTestStorage",
  *     "list_builder" = "Drupal\config_test\ConfigTestListBuilder",
  *     "form" = {
- *       "default" = "Drupal\config_test\ConfigTestForm",
+ *       "add" = "Drupal\config_test\Form\ConfigTestAddForm",
+ *       "edit" = "Drupal\config_test\Form\ConfigTestEditForm",
  *       "delete" = "Drupal\config_test\Form\ConfigTestDeleteForm"
  *     },
  *     "access" = "Drupal\config_test\ConfigTestAccessControlHandler"
diff --git a/core/modules/config/tests/config_test/src/Form/ConfigTestAddForm.php b/core/modules/config/tests/config_test/src/Form/ConfigTestAddForm.php
new file mode 100644
index 0000000..edda18f
--- /dev/null
+++ b/core/modules/config/tests/config_test/src/Form/ConfigTestAddForm.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config_test\Form\ConfigTestAddForm.
+ */
+
+namespace Drupal\config_test\Form;
+
+use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding "Test configuration" entities.
+ */
+class ConfigTestAddForm extends ConfigTestFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    drupal_set_message(String::format('%label configuration has been created.', array('%label' => $this->entity->label())));
+  }
+
+}
diff --git a/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php b/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php
index b203008..eb984c7 100644
--- a/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php
+++ b/core/modules/config/tests/config_test/src/Form/ConfigTestDeleteForm.php
@@ -7,14 +7,14 @@
 namespace Drupal\config_test\Form;
 
 use Drupal\Component\Utility\String;
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Delete confirmation form for config_test entities.
  */
-class ConfigTestDeleteForm extends EntityConfirmFormBase {
+class ConfigTestDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,8 +40,9 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message(String::format('%label configuration has been deleted.', array('%label' => $this->entity->label())));
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
diff --git a/core/modules/config/tests/config_test/src/Form/ConfigTestEditForm.php b/core/modules/config/tests/config_test/src/Form/ConfigTestEditForm.php
new file mode 100644
index 0000000..003f224
--- /dev/null
+++ b/core/modules/config/tests/config_test/src/Form/ConfigTestEditForm.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config_test\Form\ConfigTestEditForm.
+ */
+
+namespace Drupal\config_test\Form;
+
+use Drupal\Component\Utility\String;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for editing "Test configuration" entities.
+ */
+class ConfigTestEditForm extends ConfigTestFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    drupal_set_message(String::format('%label configuration has been updated.', array('%label' => $this->entity->label())));
+  }
+
+}
diff --git a/core/modules/config/tests/config_test/src/ConfigTestForm.php b/core/modules/config/tests/config_test/src/Form/ConfigTestFormBase.php
similarity index 75%
rename from core/modules/config/tests/config_test/src/ConfigTestForm.php
rename to core/modules/config/tests/config_test/src/Form/ConfigTestFormBase.php
index cb847ee..192020b 100644
--- a/core/modules/config/tests/config_test/src/ConfigTestForm.php
+++ b/core/modules/config/tests/config_test/src/Form/ConfigTestFormBase.php
@@ -2,18 +2,18 @@
 
 /**
  * @file
- * Contains Drupal\config_test\ConfigTestForm.
+ * Contains Drupal\config_test\Form\ConfigTestFormBase.
  */
 
-namespace Drupal\config_test;
+namespace Drupal\config_test\Form;
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
- * Form controller for the test config edit forms.
+ * Provides a common base form for the "Test configuration" entity.
  */
-class ConfigTestForm extends EntityForm {
+abstract class ConfigTestFormBase extends EntityForm {
 
   /**
    * {@inheritdoc}
@@ -71,15 +71,7 @@ public function form(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $entity = $this->entity;
-    $status = $entity->save();
-
-    if ($status === SAVED_UPDATED) {
-      drupal_set_message(format_string('%label configuration has been updated.', array('%label' => $entity->label())));
-    }
-    else {
-      drupal_set_message(format_string('%label configuration has been created.', array('%label' => $entity->label())));
-    }
+    parent::save($form, $form_state);
 
     $form_state->setRedirect('config_test.list_page');
   }
diff --git a/core/modules/contact/src/Entity/Category.php b/core/modules/contact/src/Entity/Category.php
index ec770e4..7b77117 100644
--- a/core/modules/contact/src/Entity/Category.php
+++ b/core/modules/contact/src/Entity/Category.php
@@ -22,8 +22,8 @@
  *     "access" = "Drupal\contact\CategoryAccessControlHandler",
  *     "list_builder" = "Drupal\contact\CategoryListBuilder",
  *     "form" = {
- *       "add" = "Drupal\contact\CategoryForm",
- *       "edit" = "Drupal\contact\CategoryForm",
+ *       "add" = "Drupal\contact\Form\CategoryAddForm",
+ *       "edit" = "Drupal\contact\Form\CategoryEditForm",
  *       "delete" = "Drupal\contact\Form\CategoryDeleteForm"
  *     }
  *   },
diff --git a/core/modules/contact/src/Form/CategoryAddForm.php b/core/modules/contact/src/Form/CategoryAddForm.php
new file mode 100644
index 0000000..a8279ba
--- /dev/null
+++ b/core/modules/contact/src/Form/CategoryAddForm.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Form\CategoryAddForm.
+ */
+
+namespace Drupal\contact\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding contact categories.
+ */
+class CategoryAddForm extends CategoryFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $category = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Category %label has been added.', array('%label' => $category->label())));
+    $this->logger('contact')->notice('Category %label has been added.', array(
+      '%label' => $category->label(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/contact/src/Form/CategoryDeleteForm.php b/core/modules/contact/src/Form/CategoryDeleteForm.php
index cd534d4..1cee026 100644
--- a/core/modules/contact/src/Form/CategoryDeleteForm.php
+++ b/core/modules/contact/src/Form/CategoryDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\contact\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Builds the form to delete a contact category.
  */
-class CategoryDeleteForm extends EntityConfirmFormBase {
+class CategoryDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,8 +40,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('Category %label has been deleted.', array('%label' => $this->entity->label())));
     $this->logger('contact')->notice('Category %label has been deleted.', array('%label' => $this->entity->label()));
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/contact/src/Form/CategoryEditForm.php b/core/modules/contact/src/Form/CategoryEditForm.php
new file mode 100644
index 0000000..be1a62a
--- /dev/null
+++ b/core/modules/contact/src/Form/CategoryEditForm.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Form\CategoryEditForm.
+ */
+
+namespace Drupal\contact\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for editing contact categories.
+ */
+class CategoryEditForm extends CategoryFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $block_type = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Category %label has been updated.', array('%label' => $block_type->label())));
+    $this->logger('contact')->notice('Category %label has been updated.', array(
+      '%label' => $block_type->label(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/contact/src/CategoryForm.php b/core/modules/contact/src/Form/CategoryFormBase.php
similarity index 80%
rename from core/modules/contact/src/CategoryForm.php
rename to core/modules/contact/src/Form/CategoryFormBase.php
index e6defb1..f442ed2 100644
--- a/core/modules/contact/src/CategoryForm.php
+++ b/core/modules/contact/src/Form/CategoryFormBase.php
@@ -2,19 +2,19 @@
 
 /**
  * @file
- * Contains \Drupal\contact\CategoryForm.
+ * Contains \Drupal\contact\Form\CategoryFormBase.
  */
 
-namespace Drupal\contact;
+namespace Drupal\contact\Form;
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
- * Base form for category edit forms.
+ * Provides a common base form for contact category forms.
  */
-class CategoryForm extends EntityForm {
+abstract class CategoryFormBase extends EntityForm {
 
   /**
    * {@inheritdoc}
@@ -92,21 +92,11 @@ public function validate(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $category = $this->entity;
-    $status = $category->save();
     $contact_settings = $this->config('contact.settings');
 
-    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
-
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message($this->t('Category %label has been updated.', array('%label' => $category->label())));
-      $this->logger('contact')->notice('Category %label has been updated.', array('%label' => $category->label(), 'link' => $edit_link));
-    }
-    else {
-      drupal_set_message($this->t('Category %label has been added.', array('%label' => $category->label())));
-      $this->logger('contact')->notice('Category %label has been added.', array('%label' => $category->label(), 'link' => $edit_link));
-    }
-
     // Update the default category.
     if ($form_state->getValue('selected')) {
       $contact_settings
diff --git a/core/modules/contact/src/MessageForm.php b/core/modules/contact/src/MessageForm.php
index 83066a3..4ebff79 100644
--- a/core/modules/contact/src/MessageForm.php
+++ b/core/modules/contact/src/MessageForm.php
@@ -264,7 +264,7 @@ public function save(array $form, FormStateInterface $form_state) {
     // Save the message. In core this is a no-op but should contrib wish to
     // implement message storage, this will make the task of swapping in a real
     // storage controller straight-forward.
-    $message->save();
+    parent::save($form, $form_state);
   }
 
   /**
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
index 9898678..2d85070 100644
--- a/core/modules/content_translation/content_translation.pages.inc
+++ b/core/modules/content_translation/content_translation.pages.inc
@@ -208,7 +208,7 @@ function content_translation_add_page(EntityInterface $entity, LanguageInterface
   $form_state['content_translation']['source'] = $source;
   $form_state['content_translation']['target'] = $target;
   $form_state['content_translation']['translation_form'] = !$entity->access('update');
-  return \Drupal::service('entity.form_builder')->getForm($entity, 'default', $form_state);
+  return \Drupal::service('entity.form_builder')->getForm($entity, 'add', $form_state);
 }
 
 /**
@@ -230,7 +230,7 @@ function content_translation_edit_page(EntityInterface $entity, LanguageInterfac
   $language = !empty($language) ? $language : \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
   $form_state['langcode'] = $language->id;
   $form_state['content_translation']['translation_form'] = TRUE;
-  return \Drupal::service('entity.form_builder')->getForm($entity, 'default', $form_state);
+  return \Drupal::service('entity.form_builder')->getForm($entity, 'edit', $form_state);
 }
 
 /**
diff --git a/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php b/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php
index 95e535f..dc7249d 100644
--- a/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php
+++ b/core/modules/entity/src/Form/EntityDisplayModeDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\entity\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides the delete form for entity display modes.
  */
-class EntityDisplayModeDeleteForm extends EntityConfirmFormBase {
+class EntityDisplayModeDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -49,12 +49,11 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     $entity_type = $this->entity->getEntityType();
     drupal_set_message(t('Deleted the %label @entity-type.', array('%label' => $this->entity->label(), '@entity-type' => $entity_type->getLowercaseLabel())));
-    $this->entity->delete();
     \Drupal::entityManager()->clearCachedFieldDefinitions();
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
diff --git a/core/modules/entity/src/Form/EntityDisplayModeFormBase.php b/core/modules/entity/src/Form/EntityDisplayModeFormBase.php
index abd8e77..b9dfd27 100644
--- a/core/modules/entity/src/Form/EntityDisplayModeFormBase.php
+++ b/core/modules/entity/src/Form/EntityDisplayModeFormBase.php
@@ -122,8 +122,9 @@ public function exists($entity_id, array $element) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message(t('Saved the %label @entity-type.', array('%label' => $this->entity->label(), '@entity-type' => $this->entityType->getLowercaseLabel())));
-    $this->entity->save();
     \Drupal::entityManager()->clearCachedFieldDefinitions();
     $form_state->setRedirect('entity.' . $this->entity->getEntityTypeId() . '_list');
   }
diff --git a/core/modules/field/src/Tests/FieldAttachOtherTest.php b/core/modules/field/src/Tests/FieldAttachOtherTest.php
index ec5dd88..c48a63c 100644
--- a/core/modules/field/src/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/src/Tests/FieldAttachOtherTest.php
@@ -331,7 +331,7 @@ function testEntityFormDisplayExtractFormValues() {
     $values_2[1]['value'] = 0;
 
     // Pretend the form has been built.
-    $form_state['build_info']['callback_object'] = \Drupal::entityManager()->getFormObject($entity_type, 'default');
+    $form_state['build_info']['callback_object'] = \Drupal::entityManager()->getFormObject($entity_type, 'add');
     \Drupal::formBuilder()->prepareForm('field_test_entity_form', $form, $form_state);
     drupal_process_form('field_test_entity_form', $form, $form_state);
     $form_state->setValue($this->fieldTestData->field_name, $values);
@@ -350,13 +350,13 @@ function testEntityFormDisplayExtractFormValues() {
         $expected_values[] = array('value' => $values[$key]['value']);
       }
     }
-    $this->assertIdentical($entity->{$this->fieldTestData->field_name}->getValue(), $expected_values, 'Submit filters empty values');
+    $this->assertIdentical($entity->{$this->fieldTestData->field_name}->getValue(), $expected_values);
     foreach ($weights_2 as $key => $value) {
       if ($key != 1) {
         $expected_values_2[] = array('value' => $values_2[$key]['value']);
       }
     }
-    $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values');
+    $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2);
 
     // Call EntityFormDisplayInterface::extractFormValues() for a single field (the second field).
     foreach ($display->getComponents() as $name => $options) {
@@ -373,7 +373,7 @@ function testEntityFormDisplayExtractFormValues() {
       }
     }
     $this->assertTrue($entity->{$this->fieldTestData->field_name}->isEmpty(), 'The first field is empty in the entity object');
-    $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values');
+    $this->assertIdentical($entity->{$this->fieldTestData->field_name_2}->getValue(), $expected_values_2);
   }
 
 }
diff --git a/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php b/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php
index 97470db..d8de78f 100644
--- a/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php
+++ b/core/modules/field_ui/src/Form/FieldInstanceConfigDeleteForm.php
@@ -68,7 +68,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $field_storage = $this->entity->getFieldStorageDefinition();
     $bundles = entity_get_bundles();
     $bundle_label = $bundles[$this->entity->entity_type][$this->entity->bundle]['label'];
diff --git a/core/modules/filter/src/FilterFormatAddForm.php b/core/modules/filter/src/FilterFormatAddForm.php
index 8c6ad4a..1fa6f73 100644
--- a/core/modules/filter/src/FilterFormatAddForm.php
+++ b/core/modules/filter/src/FilterFormatAddForm.php
@@ -24,8 +24,8 @@ public function form(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
     drupal_set_message($this->t('Added text format %format.', array('%format' => $this->entity->label())));
     return $this->entity;
   }
diff --git a/core/modules/filter/src/FilterFormatEditForm.php b/core/modules/filter/src/FilterFormatEditForm.php
index ab437ac..a32e73f 100644
--- a/core/modules/filter/src/FilterFormatEditForm.php
+++ b/core/modules/filter/src/FilterFormatEditForm.php
@@ -32,8 +32,8 @@ public function form(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
     drupal_set_message($this->t('The text format %format has been updated.', array('%format' => $this->entity->label())));
     return $this->entity;
   }
diff --git a/core/modules/filter/src/FilterFormatFormBase.php b/core/modules/filter/src/FilterFormatFormBase.php
index 65159dd..b6077a3 100644
--- a/core/modules/filter/src/FilterFormatFormBase.php
+++ b/core/modules/filter/src/FilterFormatFormBase.php
@@ -249,10 +249,16 @@ public function submit(array $form, FormStateInterface $form_state) {
         }
       }
     }
-    $format->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     // Save user permissions.
-    if ($permission = $format->getPermissionName()) {
+    if ($permission = $this->entity->getPermissionName()) {
       foreach ($form_state->getValue('roles') as $rid => $enabled) {
         user_role_change_permissions($rid, array($permission => $enabled));
       }
diff --git a/core/modules/forum/src/Form/ForumForm.php b/core/modules/forum/src/Form/ForumForm.php
index 8ee5f43..73be334 100644
--- a/core/modules/forum/src/Form/ForumForm.php
+++ b/core/modules/forum/src/Form/ForumForm.php
@@ -8,12 +8,12 @@
 namespace Drupal\forum\Form;
 
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\taxonomy\TermForm;
+use Drupal\taxonomy\Form\TermFormBase;
 
 /**
  * Base form for forum term edit forms.
  */
-class ForumForm extends TermForm {
+class ForumForm extends TermFormBase {
 
   /**
    * Reusable type field to use in status messages.
@@ -79,6 +79,7 @@ public function save(array $form, FormStateInterface $form_state) {
     $term_storage = $this->entityManager->getStorage('taxonomy_term');
     $status = $term_storage->save($term);
 
+    // @todo Split this into dedicated add and edit forms.
     switch ($status) {
       case SAVED_NEW:
         drupal_set_message($this->t('Created new @type %term.', array('%term' => $term->getName(), '@type' => $this->forumFormType)));
diff --git a/core/modules/image/src/Form/ImageStyleDeleteForm.php b/core/modules/image/src/Form/ImageStyleDeleteForm.php
index e490fa6..05538d1 100644
--- a/core/modules/image/src/Form/ImageStyleDeleteForm.php
+++ b/core/modules/image/src/Form/ImageStyleDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\image\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Creates a form to delete an image style.
  */
-class ImageStyleDeleteForm extends EntityConfirmFormBase {
+class ImageStyleDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -64,7 +64,14 @@ public function form(array $form, FormStateInterface $form_state) {
    */
   public function submit(array $form, FormStateInterface $form_state) {
     $this->entity->set('replacementID', $form_state->getValue('replacement'));
-    $this->entity->delete();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('Style %name was deleted.', array('%name' => $this->entity->label())));
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
diff --git a/core/modules/image/src/Form/ImageStyleEditForm.php b/core/modules/image/src/Form/ImageStyleEditForm.php
index bcd9c52..4e18c75 100644
--- a/core/modules/image/src/Form/ImageStyleEditForm.php
+++ b/core/modules/image/src/Form/ImageStyleEditForm.php
@@ -248,13 +248,19 @@ public function effectSave($form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
+    parent::submit($form, $form_state);
 
     // Update image effect weights.
     if (!$form_state->isValueEmpty('effects')) {
       $this->updateEffectWeights($form_state->getValue('effects'));
     }
+  }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
     parent::save($form, $form_state);
     drupal_set_message($this->t('Changes to the style have been saved.'));
   }
diff --git a/core/modules/image/src/Form/ImageStyleFormBase.php b/core/modules/image/src/Form/ImageStyleFormBase.php
index af35482..776df8c 100644
--- a/core/modules/image/src/Form/ImageStyleFormBase.php
+++ b/core/modules/image/src/Form/ImageStyleFormBase.php
@@ -77,7 +77,8 @@ public function form(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $this->entity->save();
+    parent::save($form, $form_state);
+
     $form_state->setRedirectUrl($this->entity->urlInfo('edit-form'));
   }
 
diff --git a/core/modules/language/src/Form/LanguageDeleteForm.php b/core/modules/language/src/Form/LanguageDeleteForm.php
index 26c83a2..54c3ca5 100644
--- a/core/modules/language/src/Form/LanguageDeleteForm.php
+++ b/core/modules/language/src/Form/LanguageDeleteForm.php
@@ -106,7 +106,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     // @todo This should be replaced with $this->entity->delete() when the
     //   additional logic in language_delete() is ported.
     $success = language_delete($this->entity->id());
diff --git a/core/modules/menu_link_content/menu_link_content.routing.yml b/core/modules/menu_link_content/menu_link_content.routing.yml
index dfecfdb..ec25880 100644
--- a/core/modules/menu_link_content/menu_link_content.routing.yml
+++ b/core/modules/menu_link_content/menu_link_content.routing.yml
@@ -9,7 +9,7 @@ menu_link_content.link_add:
 entity.menu_link_content.canonical:
   path: '/admin/structure/menu/item/{menu_link_content}/edit'
   defaults:
-    _entity_form: 'menu_link_content.default'
+    _entity_form: 'menu_link_content.edit'
     _title: 'Edit menu link'
   options:
   # @todo Remove once https://www.drupal.org/node/2310475 is in.
diff --git a/core/modules/menu_link_content/src/Controller/MenuController.php b/core/modules/menu_link_content/src/Controller/MenuController.php
index 81bbd40..311e084 100644
--- a/core/modules/menu_link_content/src/Controller/MenuController.php
+++ b/core/modules/menu_link_content/src/Controller/MenuController.php
@@ -31,7 +31,7 @@ public function addLink(MenuInterface $menu) {
       'menu_name' => $menu->id(),
       'bundle' => 'menu_link_content',
     ));
-    return $this->entityFormBuilder()->getForm($menu_link);
+    return $this->entityFormBuilder()->getForm($menu_link, 'add');
   }
 
 }
diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
index 11f1d12..cc5a1fd 100644
--- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -24,7 +24,8 @@
  *     "storage" = "Drupal\Core\Entity\ContentEntityDatabaseStorage",
  *     "access" = "Drupal\menu_link_content\MenuLinkContentAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\menu_link_content\Form\MenuLinkContentForm",
+ *       "add" = "Drupal\menu_link_content\Form\MenuLinkContentAddForm",
+ *       "edit" = "Drupal\menu_link_content\Form\MenuLinkContentEditForm",
  *       "delete" = "Drupal\menu_link_content\Form\MenuLinkContentDeleteForm"
  *     }
  *   },
diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentAddForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentAddForm.php
new file mode 100644
index 0000000..eb1facf
--- /dev/null
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentAddForm.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\menu_link_content\Form\MenuLinkContentAddForm.
+ */
+
+namespace Drupal\menu_link_content\Form;
+
+/**
+ * Provides a form for adding content menu links.
+ */
+class MenuLinkContentAddForm extends MenuLinkContentFormBase {
+}
diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php
index c5a7232..c4e1617 100644
--- a/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentDeleteForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\menu_link_content\Form;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
@@ -17,7 +17,7 @@
 /**
  * Provides a delete form for content menu links.
  */
-class MenuLinkContentDeleteForm extends ContentEntityConfirmFormBase {
+class MenuLinkContentDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * Logger channel.
@@ -66,9 +66,10 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $t_args = array('%title' => $this->entity->getTitle());
-    $this->entity->delete();
     drupal_set_message($this->t('The menu link %title has been deleted.', $t_args));
     $this->logger->notice('Deleted menu link %title.', $t_args);
     $form_state->setRedirect('<front>');
diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentEditForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentEditForm.php
new file mode 100644
index 0000000..51d3a312
--- /dev/null
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentEditForm.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\menu_link_content\Form\MenuLinkContentEditForm.
+ */
+
+namespace Drupal\menu_link_content\Form;
+
+/**
+ * Provides a form for adding content menu links.
+ */
+class MenuLinkContentEditForm extends MenuLinkContentFormBase {
+}
diff --git a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentFormBase.php
similarity index 98%
rename from core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
rename to core/modules/menu_link_content/src/Form/MenuLinkContentFormBase.php
index ce2d81d..3f26e90 100644
--- a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentFormBase.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\menu_link_content\Form\MenuLinkContentForm.
+ * Contains \Drupal\menu_link_content\Form\MenuLinkContentFormBase.
  */
 
 namespace Drupal\menu_link_content\Form;
@@ -27,13 +27,13 @@
 use Symfony\Component\Routing\RequestContext;
 
 /**
- * Provides a form to add/update content menu links.
+ * Provides a base form for content menu link forms.
  *
  * Note: This is not only a content entity form, but also implements the
  * MenuLinkFormInterface, so the same class can be used in places expecting a
  * generic menu link plugin configuration form.
  */
-class MenuLinkContentForm extends ContentEntityForm implements MenuLinkFormInterface {
+abstract class MenuLinkContentFormBase extends ContentEntityForm implements MenuLinkFormInterface {
 
   /**
    * The content menu link.
@@ -78,7 +78,7 @@ class MenuLinkContentForm extends ContentEntityForm implements MenuLinkFormInter
   protected $account;
 
   /**
-   * Constructs a MenuLinkContentForm object.
+   * Constructs a MenuLinkContentFormBase object.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index 07fcb81..3da2d4e 100644
--- a/core/modules/menu_ui/menu_ui.module
+++ b/core/modules/menu_ui/menu_ui.module
@@ -69,8 +69,8 @@ function menu_ui_permission() {
 function menu_ui_entity_type_build(array &$entity_types) {
   /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
   $entity_types['menu']
-    ->setFormClass('add', 'Drupal\menu_ui\MenuForm')
-    ->setFormClass('edit', 'Drupal\menu_ui\MenuForm')
+    ->setFormClass('add', 'Drupal\menu_ui\Form\MenuAddForm')
+    ->setFormClass('edit', 'Drupal\menu_ui\Form\MenuEditForm')
     ->setFormClass('delete', 'Drupal\menu_ui\Form\MenuDeleteForm')
     ->setListBuilderClass('Drupal\menu_ui\MenuListBuilder')
     ->setLinkTemplate('add-form', 'menu_ui.menu_add')
diff --git a/core/modules/menu_ui/src/Form/MenuAddForm.php b/core/modules/menu_ui/src/Form/MenuAddForm.php
new file mode 100644
index 0000000..3883b73
--- /dev/null
+++ b/core/modules/menu_ui/src/Form/MenuAddForm.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_ui\Form\MenuAddForm.
+ */
+
+namespace Drupal\menu_ui\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding menus.
+ */
+class MenuAddForm extends MenuFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $menu = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Menu %label has been added.', array('%label' => $menu->label())));
+    $this->logger('menu')->notice('Menu %label has been added.', array('%label' => $menu->label(), 'link' => $edit_link));
+  }
+
+}
diff --git a/core/modules/menu_ui/src/Form/MenuDeleteForm.php b/core/modules/menu_ui/src/Form/MenuDeleteForm.php
index 299df36..f4b7c5b 100644
--- a/core/modules/menu_ui/src/Form/MenuDeleteForm.php
+++ b/core/modules/menu_ui/src/Form/MenuDeleteForm.php
@@ -92,7 +92,7 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     $form_state->setRedirect('menu_ui.overview_page');
 
     // Locked menus may not be deleted.
diff --git a/core/modules/menu_ui/src/Form/MenuEditForm.php b/core/modules/menu_ui/src/Form/MenuEditForm.php
new file mode 100644
index 0000000..af1a028
--- /dev/null
+++ b/core/modules/menu_ui/src/Form/MenuEditForm.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu_ui\Form\MenuEditForm.
+ */
+
+namespace Drupal\menu_ui\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for editing menus.
+ */
+class MenuEditForm extends MenuFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $menu = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Menu %label has been updated.', array('%label' => $menu->label())));
+    $this->logger('menu')->notice('Menu %label has been updated.', array('%label' => $menu->label(), 'link' => $edit_link));
+  }
+
+}
diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/Form/MenuFormBase.php
similarity index 94%
rename from core/modules/menu_ui/src/MenuForm.php
rename to core/modules/menu_ui/src/Form/MenuFormBase.php
index 2b3758f..c54ef86 100644
--- a/core/modules/menu_ui/src/MenuForm.php
+++ b/core/modules/menu_ui/src/Form/MenuFormBase.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\menu_ui\MenuForm.
+ * Contains \Drupal\menu_ui\Form\MenuFormBase.
  */
 
-namespace Drupal\menu_ui;
+namespace Drupal\menu_ui\Form;
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\EntityForm;
@@ -22,9 +22,9 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Base form for menu edit forms.
+ * Provides a base form for menu forms.
  */
-class MenuForm extends EntityForm {
+abstract class MenuFormBase extends EntityForm {
 
   /**
    * The factory for entity queries.
@@ -62,7 +62,7 @@ class MenuForm extends EntityForm {
   protected $overviewTreeForm = array('#tree' => TRUE);
 
   /**
-   * Constructs a MenuForm object.
+   * Constructs a MenuFormBase object.
    *
    * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
    *   The factory for entity queries.
@@ -174,23 +174,20 @@ public function menuNameExists($value) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
+    parent::submit($form, $form_state);
+
     $menu = $this->entity;
     if (!$menu->isNew() || $menu->isLocked()) {
       $this->submitOverviewForm($form, $form_state);
     }
+  }
 
-    $status = $menu->save();
-
-    $edit_link = $this->linkGenerator->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message($this->t('Menu %label has been updated.', array('%label' => $menu->label())));
-      $this->logger('menu')->notice('Menu %label has been updated.', array('%label' => $menu->label(), 'link' => $edit_link));
-    }
-    else {
-      drupal_set_message($this->t('Menu %label has been added.', array('%label' => $menu->label())));
-      $this->logger('menu')->notice('Menu %label has been added.', array('%label' => $menu->label(), 'link' => $edit_link));
-    }
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     $form_state->setRedirectUrl($this->entity->urlInfo('edit-form'));
   }
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 7238abe..08e898b 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -401,7 +401,7 @@ function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) {
 /**
  * Perform node validation before a node is created or updated.
  *
- * This hook is invoked from NodeForm::validate(), after a user has
+ * This hook is invoked from NodeFormBase::validate(), after a user has
  * finished editing the node and is previewing or submitting it. It is invoked
  * at the end of all the standard validation steps.
  *
diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php
index e983eee..011e63a 100644
--- a/core/modules/node/src/Controller/NodeController.php
+++ b/core/modules/node/src/Controller/NodeController.php
@@ -101,7 +101,7 @@ public function add(NodeTypeInterface $node_type) {
       'langcode' => $langcode ? $langcode : $this->languageManager()->getCurrentLanguage()->id,
     ));
 
-    $form = $this->entityFormBuilder()->getForm($node);
+    $form = $this->entityFormBuilder()->getForm($node, 'add');
 
     return $form;
   }
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index 928976b..13c04af 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -28,9 +28,9 @@
  *     "view_builder" = "Drupal\node\NodeViewBuilder",
  *     "access" = "Drupal\node\NodeAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\node\NodeForm",
+ *       "add" = "Drupal\node\Form\NodeAddForm",
+ *       "edit" = "Drupal\node\Form\NodeEditForm",
  *       "delete" = "Drupal\node\Form\NodeDeleteForm",
- *       "edit" = "Drupal\node\NodeForm"
  *     },
  *     "list_builder" = "Drupal\node\NodeListBuilder",
  *     "translation" = "Drupal\node\NodeTranslationHandler"
diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php
index 57fc6f6..70e6ed3 100644
--- a/core/modules/node/src/Entity/NodeType.php
+++ b/core/modules/node/src/Entity/NodeType.php
@@ -21,8 +21,8 @@
  *   controllers = {
  *     "access" = "Drupal\node\NodeTypeAccessControlHandler",
  *     "form" = {
- *       "add" = "Drupal\node\NodeTypeForm",
- *       "edit" = "Drupal\node\NodeTypeForm",
+ *       "add" = "Drupal\node\Form\NodeTypeAddForm",
+ *       "edit" = "Drupal\node\Form\NodeTypeEditForm",
  *       "delete" = "Drupal\node\Form\NodeTypeDeleteConfirm"
  *     },
  *     "list_builder" = "Drupal\node\NodeTypeListBuilder",
diff --git a/core/modules/node/src/Form/NodeAddForm.php b/core/modules/node/src/Form/NodeAddForm.php
new file mode 100644
index 0000000..780bd46
--- /dev/null
+++ b/core/modules/node/src/Form/NodeAddForm.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Form\NodeAddForm.
+ */
+
+namespace Drupal\node\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding nodes.
+ */
+class NodeAddForm extends NodeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    /** @var \Drupal\node\NodeInterface $node */
+    $node = $this->entity;
+    $node_type = $this->entityManager->getStorage('node_type')->load($node->getType());
+    $t_args = array('@type' => $node_type->label(), '%title' => $node->label());
+    $log_context = array(
+      '@type' => $node->getType(),
+      '%title' => $node->label(),
+      'link' => $this->l($this->t('View'), 'node.view', array('node' => $node->id())),
+    );
+
+    drupal_set_message(t('@type %title has been created.', $t_args));
+    $this->logger('content')->notice('@type: added %title.', $log_context);
+  }
+
+}
diff --git a/core/modules/node/src/Form/NodeDeleteForm.php b/core/modules/node/src/Form/NodeDeleteForm.php
index c3de373..08f6840 100644
--- a/core/modules/node/src/Form/NodeDeleteForm.php
+++ b/core/modules/node/src/Form/NodeDeleteForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node\Form;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
@@ -16,7 +16,7 @@
 /**
  * Provides a form for deleting a node.
  */
-class NodeDeleteForm extends ContentEntityConfirmFormBase {
+class NodeDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * The URL generator.
@@ -72,8 +72,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $this->logger('content')->notice('@type: deleted %title.', array('@type' => $this->entity->bundle(), '%title' => $this->entity->label()));
     $node_type_storage = $this->entityManager->getStorage('node_type');
     $node_type = $node_type_storage->load($this->entity->bundle())->label();
diff --git a/core/modules/node/src/Form/NodeEditForm.php b/core/modules/node/src/Form/NodeEditForm.php
new file mode 100644
index 0000000..ad7c4be
--- /dev/null
+++ b/core/modules/node/src/Form/NodeEditForm.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Form\NodeEditForm.
+ */
+
+namespace Drupal\node\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for editing nodes.
+ */
+class NodeEditForm extends NodeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    /** @var \Drupal\node\NodeInterface $node */
+    $node = $this->entity;
+    $node_type = $this->entityManager->getStorage('node_type')->load($node->getType());
+    $t_args = array('@type' => $node_type->label(), '%title' => $node->label());
+    $log_context = array(
+      '@type' => $node->getType(),
+      '%title' => $node->label(),
+      'link' => $this->l($this->t('View'), 'node.view', array('node' => $node->id())),
+    );
+
+    drupal_set_message(t('@type %title has been updated.', $t_args));
+    $this->logger('content')->notice('@type: updated %title.', $log_context);
+  }
+
+}
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/Form/NodeFormBase.php
similarity index 95%
rename from core/modules/node/src/NodeForm.php
rename to core/modules/node/src/Form/NodeFormBase.php
index a2ec826..2eb4669 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/Form/NodeFormBase.php
@@ -2,22 +2,24 @@
 
 /**
  * @file
- * Definition of Drupal\node\NodeForm.
+ * Definition of Drupal\node\Form\NodeFormBase.
  */
 
-namespace Drupal\node;
+namespace Drupal\node\Form;
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Component\Utility\String;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Form controller for the node edit forms.
+ * Provides a base form for nodes.
  */
-class NodeForm extends ContentEntityForm {
+abstract class NodeFormBase extends ContentEntityForm {
 
   /**
    * Default settings for this content/node type.
@@ -429,21 +431,9 @@ public function buildEntity(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $node = $this->entity;
-    $insert = $node->isNew();
-    $node->save();
-    $node_link = l(t('View'), 'node/' . $node->id());
-    $context = array('@type' => $node->getType(), '%title' => $node->label(), 'link' => $node_link);
-    $t_args = array('@type' => node_get_type_label($node), '%title' => $node->label());
-
-    if ($insert) {
-      $this->logger('content')->notice('@type: added %title.', $context);
-      drupal_set_message(t('@type %title has been created.', $t_args));
-    }
-    else {
-      $this->logger('content')->notice('@type: updated %title.', $context);
-      drupal_set_message(t('@type %title has been updated.', $t_args));
-    }
 
     if ($node->id()) {
       $form_state->setValue('nid', $node->id());
diff --git a/core/modules/node/src/Form/NodeTypeAddForm.php b/core/modules/node/src/Form/NodeTypeAddForm.php
new file mode 100644
index 0000000..f09d2ee
--- /dev/null
+++ b/core/modules/node/src/Form/NodeTypeAddForm.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Form\NodeTypeAddForm.
+ */
+
+namespace Drupal\node\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding node types.
+ */
+class NodeTypeAddForm extends NodeTypeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $type = $this->entity;
+    $t_args = array('%name' => $type->label());
+
+    drupal_set_message(t('The content type %name has been added.', $t_args));
+    $context = array_merge($t_args, array('link' => l(t('View'), 'admin/structure/types')));
+    $this->logger('node')->notice('Added content type %name.', $context);
+  }
+
+}
diff --git a/core/modules/node/src/Form/NodeTypeDeleteConfirm.php b/core/modules/node/src/Form/NodeTypeDeleteConfirm.php
index 3631b33..1dadc75 100644
--- a/core/modules/node/src/Form/NodeTypeDeleteConfirm.php
+++ b/core/modules/node/src/Form/NodeTypeDeleteConfirm.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\node\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -16,7 +16,7 @@
 /**
  * Provides a form for content type deletion.
  */
-class NodeTypeDeleteConfirm extends EntityConfirmFormBase {
+class NodeTypeDeleteConfirm extends EntityDeleteFormBase {
 
   /**
    * The database connection.
@@ -83,8 +83,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $t_args = array('%name' => $this->entity->label());
     drupal_set_message(t('The content type %name has been deleted.', $t_args));
     $this->logger('node')->notice('Deleted content type %name.', $t_args);
diff --git a/core/modules/node/src/Form/NodeTypeEditForm.php b/core/modules/node/src/Form/NodeTypeEditForm.php
new file mode 100644
index 0000000..d9c7774
--- /dev/null
+++ b/core/modules/node/src/Form/NodeTypeEditForm.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Form\NodeTypeEditForm.
+ */
+
+namespace Drupal\node\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding node types.
+ */
+class NodeTypeEditForm extends NodeTypeFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $type = $this->entity;
+    $t_args = array('%name' => $type->label());
+
+    drupal_set_message(t('The content type %name has been updated.', $t_args));
+  }
+
+}
diff --git a/core/modules/node/src/NodeTypeForm.php b/core/modules/node/src/Form/NodeTypeFormBase.php
similarity index 90%
rename from core/modules/node/src/NodeTypeForm.php
rename to core/modules/node/src/Form/NodeTypeFormBase.php
index c99045f..abcc0b5 100644
--- a/core/modules/node/src/NodeTypeForm.php
+++ b/core/modules/node/src/Form/NodeTypeFormBase.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\node\NodeTypeForm.
+ * Contains \Drupal\node\Form\NodeTypeFormBase.
  */
 
-namespace Drupal\node;
+namespace Drupal\node\Form;
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Component\Utility\String;
@@ -13,9 +13,9 @@
 use Drupal\Core\Form\FormStateInterface;
 
 /**
- * Form controller for node type forms.
+ * Provides a common base form for node type forms.
  */
-class NodeTypeForm extends EntityForm {
+abstract class NodeTypeFormBase extends EntityForm {
 
   /**
    * {@inheritdoc}
@@ -176,23 +176,19 @@ public function validate(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
+    parent::submit($form, $form_state);
+
     $type = $this->entity;
     $type->type = trim($type->id());
     $type->name = trim($type->name);
+  }
 
-    $status = $type->save();
-
-    $t_args = array('%name' => $type->label());
-
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message(t('The content type %name has been updated.', $t_args));
-    }
-    elseif ($status == SAVED_NEW) {
-      drupal_set_message(t('The content type %name has been added.', $t_args));
-      $context = array_merge($t_args, array('link' => l(t('View'), 'admin/structure/types')));
-      $this->logger('node')->notice('Added content type %name.', $context);
-    }
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     $form_state->setRedirect('node.overview_types');
   }
diff --git a/core/modules/node/src/NodeTypeListBuilder.php b/core/modules/node/src/NodeTypeListBuilder.php
index 779672a..d10a4b4 100644
--- a/core/modules/node/src/NodeTypeListBuilder.php
+++ b/core/modules/node/src/NodeTypeListBuilder.php
@@ -31,7 +31,7 @@ class NodeTypeListBuilder extends ConfigEntityListBuilder {
   protected $urlGenerator;
 
   /**
-   * Constructs a NodeTypeForm object.
+   * Constructs a NodeTypeFormBase object.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
    *   The entity type definition.
diff --git a/core/modules/options/src/Tests/OptionsFieldTest.php b/core/modules/options/src/Tests/OptionsFieldTest.php
index 8832326..81c893b 100644
--- a/core/modules/options/src/Tests/OptionsFieldTest.php
+++ b/core/modules/options/src/Tests/OptionsFieldTest.php
@@ -29,7 +29,7 @@ class OptionsFieldTest extends OptionsFieldUnitTestBase {
   function testUpdateAllowedValues() {
     // All three options appear.
     $entity = entity_create('entity_test');
-    $form = \Drupal::service('entity.form_builder')->getForm($entity);
+    $form = \Drupal::service('entity.form_builder')->getForm($entity, 'add');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists');
@@ -55,7 +55,7 @@ function testUpdateAllowedValues() {
     $this->fieldStorage->settings['allowed_values'] = array(2 => 'Two');
     $this->fieldStorage->save();
     $entity = entity_create('entity_test');
-    $form = \Drupal::service('entity.form_builder')->getForm($entity);
+    $form = \Drupal::service('entity.form_builder')->getForm($entity, 'add');
     $this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists');
     $this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist');
@@ -66,7 +66,7 @@ function testUpdateAllowedValues() {
     // The entity holds an outdated field object with the old allowed values
     // setting, so we need to reintialize the entity object.
     $entity = entity_create('entity_test');
-    $form = \Drupal::service('entity.form_builder')->getForm($entity);
+    $form = \Drupal::service('entity.form_builder')->getForm($entity, 'add');
     $this->assertTrue(empty($form[$this->fieldName]['widget'][1]), 'Option 1 does not exist');
     $this->assertTrue(empty($form[$this->fieldName]['widget'][2]), 'Option 2 does not exist');
     $this->assertTrue(empty($form[$this->fieldName]['widget'][3]), 'Option 3 does not exist');
@@ -87,7 +87,7 @@ function testUpdateAllowedValues() {
       ))
       ->save();
     $entity = entity_create('entity_test');
-    $form = \Drupal::service('entity.form_builder')->getForm($entity);
+    $form = \Drupal::service('entity.form_builder')->getForm($entity, 'add');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][1]), 'Option 1 exists');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][2]), 'Option 2 exists');
     $this->assertTrue(!empty($form[$this->fieldName]['widget'][3]), 'Option 3 exists');
diff --git a/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php b/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php
index c15d823..cc32d07 100644
--- a/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php
+++ b/core/modules/responsive_image/src/Form/ResponsiveImageMappingDeleteForm.php
@@ -7,11 +7,11 @@
 
 namespace Drupal\responsive_image\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
-class ResponsiveImageMappingDeleteForm extends EntityConfirmFormBase {
+class ResponsiveImageMappingDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -37,8 +37,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('Responsive image mapping %label has been deleted.', array('%label' => $this->entity->label())));
     $this->logger('responsive_image')->notice('Responsive image mapping %label has been deleted.', array('%label' => $this->entity->label()));
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/responsive_image/src/ResponsiveImageMappingForm.php b/core/modules/responsive_image/src/ResponsiveImageMappingForm.php
index d1510dd..a34c177 100644
--- a/core/modules/responsive_image/src/ResponsiveImageMappingForm.php
+++ b/core/modules/responsive_image/src/ResponsiveImageMappingForm.php
@@ -121,9 +121,10 @@ public function validate(array $form, FormStateInterface $form_state) {
    * Overrides Drupal\Core\Entity\EntityForm::save().
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     /** @var \Drupal\responsive_image\ResponsiveImageMappingInterface $responsive_image_mapping */
     $responsive_image_mapping = $this->entity;
-    $responsive_image_mapping->save();
 
     $this->logger('responsive_image')->notice('Responsive image mapping @label saved.', array('@label' => $responsive_image_mapping->label()));
     drupal_set_message($this->t('Responsive image mapping %label saved.', array('%label' => $responsive_image_mapping->label())));
diff --git a/core/modules/search/src/Form/SearchPageDeleteForm.php b/core/modules/search/src/Form/SearchPageDeleteForm.php
index 8797961..7ed977c 100644
--- a/core/modules/search/src/Form/SearchPageDeleteForm.php
+++ b/core/modules/search/src/Form/SearchPageDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\search\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a deletion confirm form for search.
  */
-class SearchPageDeleteForm extends EntityConfirmFormBase {
+class SearchPageDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,8 +40,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $form_state->setRedirectUrl($this->getCancelUrl());
     drupal_set_message($this->t('The %label search page has been deleted.', array('%label' => $this->entity->label())));
   }
diff --git a/core/modules/search/src/Form/SearchPageFormBase.php b/core/modules/search/src/Form/SearchPageFormBase.php
index 7c49fd8..cbc24b0 100644
--- a/core/modules/search/src/Form/SearchPageFormBase.php
+++ b/core/modules/search/src/Form/SearchPageFormBase.php
@@ -177,7 +177,7 @@ public function submit(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $this->entity->save();
+    parent::save($form, $form_state);
 
     $form_state->setRedirect('search.settings');
   }
diff --git a/core/modules/shortcut/src/Form/ShortcutDeleteForm.php b/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
index 8172fb4..ecdf3b9 100644
--- a/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
+++ b/core/modules/shortcut/src/Form/ShortcutDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\shortcut\Form;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Builds the shortcut link deletion form.
  */
-class ShortcutDeleteForm extends ContentEntityConfirmFormBase {
+class ShortcutDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -49,8 +49,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $form_state->setRedirectUrl($this->getCancelUrl());
     drupal_set_message($this->t('The shortcut %title has been deleted.', array('%title' => $this->entity->title->value)));
   }
diff --git a/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php b/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php
index 4be29ca..e38bccc 100644
--- a/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php
+++ b/core/modules/shortcut/src/Form/ShortcutSetDeleteForm.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\shortcut\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\shortcut\ShortcutSetStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -16,7 +16,7 @@
 /**
  * Builds the shortcut set deletion form.
  */
-class ShortcutSetDeleteForm extends EntityConfirmFormBase {
+class ShortcutSetDeleteForm extends EntityDeleteFormBase {
 
   /**
    * The database connection.
@@ -101,8 +101,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $form_state->setRedirect('shortcut.set_admin');
     drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $this->entity->label())));
   }
diff --git a/core/modules/shortcut/src/ShortcutForm.php b/core/modules/shortcut/src/ShortcutForm.php
index 1c70d52..ec2d4e5 100644
--- a/core/modules/shortcut/src/ShortcutForm.php
+++ b/core/modules/shortcut/src/ShortcutForm.php
@@ -76,9 +76,11 @@ public function validate(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $entity = $this->entity;
-    $entity->save();
 
+    // @todo Split this into dedicated add and edit forms.
     if ($entity->isNew()) {
       $message = $this->t('The shortcut %link has been updated.', array('%link' => $entity->getTitle()));
     }
diff --git a/core/modules/shortcut/src/ShortcutSetForm.php b/core/modules/shortcut/src/ShortcutSetForm.php
index cb5f43f..14e6461 100644
--- a/core/modules/shortcut/src/ShortcutSetForm.php
+++ b/core/modules/shortcut/src/ShortcutSetForm.php
@@ -64,10 +64,12 @@ public function validate(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $entity = $this->entity;
     $is_new = !$entity->getOriginalId();
-    $entity->save();
 
+    // @todo Split this form into dedicated add and edit forms.
     if ($is_new) {
       drupal_set_message(t('The %set_name shortcut set has been created. You can edit it from this page.', array('%set_name' => $entity->label())));
     }
diff --git a/core/modules/system/src/Form/DateFormatAddForm.php b/core/modules/system/src/Form/DateFormatAddForm.php
index 22333e7..06eb38d 100644
--- a/core/modules/system/src/Form/DateFormatAddForm.php
+++ b/core/modules/system/src/Form/DateFormatAddForm.php
@@ -26,8 +26,8 @@ protected function actions(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
     drupal_set_message(t('Custom date format added.'));
   }
 
diff --git a/core/modules/system/src/Form/DateFormatDeleteForm.php b/core/modules/system/src/Form/DateFormatDeleteForm.php
index a97b94a..56d3024 100644
--- a/core/modules/system/src/Form/DateFormatDeleteForm.php
+++ b/core/modules/system/src/Form/DateFormatDeleteForm.php
@@ -8,7 +8,7 @@
 namespace Drupal\system\Form;
 
 use Drupal\Core\Datetime\DateFormatter;
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -16,7 +16,7 @@
 /**
  * Builds a form to delete a date format.
  */
-class DateFormatDeleteForm extends EntityConfirmFormBase {
+class DateFormatDeleteForm extends EntityDeleteFormBase {
 
   /**
    * The date formatter service.
@@ -71,8 +71,9 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message(t('Removed date format %format.', array('%format' => $this->entity->label())));
 
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/system/src/Form/DateFormatEditForm.php b/core/modules/system/src/Form/DateFormatEditForm.php
index 84fda1c..ca739cc 100644
--- a/core/modules/system/src/Form/DateFormatEditForm.php
+++ b/core/modules/system/src/Form/DateFormatEditForm.php
@@ -40,8 +40,8 @@ protected function actions(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
     drupal_set_message(t('Custom date format updated.'));
   }
 
diff --git a/core/modules/system/src/Form/DateFormatFormBase.php b/core/modules/system/src/Form/DateFormatFormBase.php
index 311f5db..fcf07dc 100644
--- a/core/modules/system/src/Form/DateFormatFormBase.php
+++ b/core/modules/system/src/Form/DateFormatFormBase.php
@@ -174,11 +174,18 @@ public function validate(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function submit(array $form, FormStateInterface $form_state) {
-    $form_state->setRedirect('system.date_format_list');
     $form_state->setValue('pattern', trim($form_state->getValue('date_format_pattern')));
 
     parent::submit($form, $form_state);
-    $this->entity->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $form_state->setRedirect('system.date_format_list');
   }
 
 }
diff --git a/core/modules/system/src/Tests/Ajax/MultiFormTest.php b/core/modules/system/src/Tests/Ajax/MultiFormTest.php
index 44de1a2..2dcbcc8 100644
--- a/core/modules/system/src/Tests/Ajax/MultiFormTest.php
+++ b/core/modules/system/src/Tests/Ajax/MultiFormTest.php
@@ -60,8 +60,8 @@ function testMultiForm() {
     // desired elements.
     $field_name = 'field_ajax_test';
     $field_xpaths = array(
-      'page-node-form' => '//form[@id="page-node-form"]//div[contains(@class, "field-name-field-ajax-test")]',
-      'page-node-form--2' => '//form[@id="page-node-form--2"]//div[contains(@class, "field-name-field-ajax-test")]',
+      'page-node-add-form' => '//form[@id="page-node-add-form"]//div[contains(@class, "field-name-field-ajax-test")]',
+      'page-node-add-form--2' => '//form[@id="page-node-add-form--2"]//div[contains(@class, "field-name-field-ajax-test")]',
     );
     $button_name = $field_name . '_add_more';
     $button_value = t('Add another item');
diff --git a/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php b/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php
index 246b053..5bbe653 100644
--- a/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php
@@ -74,7 +74,7 @@ function testEntityFormLanguage() {
     // Explicitly set form langcode.
     $langcode = $this->langcodes[0];
     $form_state['langcode'] = $langcode;
-    \Drupal::service('entity.form_builder')->getForm($node, 'default', $form_state);
+    \Drupal::service('entity.form_builder')->getForm($node, 'add', $form_state);
     $form_langcode = \Drupal::state()->get('entity_test.form_langcode') ?: FALSE;
     $this->assertTrue($langcode == $form_langcode, 'Form language is the same as the language parameter.');
 
diff --git a/core/modules/system/src/Tests/Form/RebuildTest.php b/core/modules/system/src/Tests/Form/RebuildTest.php
index 7e5a39b..c06660d 100644
--- a/core/modules/system/src/Tests/Form/RebuildTest.php
+++ b/core/modules/system/src/Tests/Form/RebuildTest.php
@@ -88,7 +88,7 @@ function testPreserveFormActionAfterAJAX() {
     // submission and verify it worked by ensuring the updated page has two text
     // field items in the field for which we just added an item.
     $this->drupalGet('node/add/page');
-    $this->drupalPostAjaxForm(NULL, array(), array('field_ajax_test_add_more' => t('Add another item')), 'system/ajax', array(), array(), 'page-node-form');
+    $this->drupalPostAjaxForm(NULL, array(), array('field_ajax_test_add_more' => t('Add another item')), 'system/ajax', array(), array(), 'page-node-add-form');
     $this->assert(count($this->xpath('//div[contains(@class, "field-name-field-ajax-test")]//input[@type="text"]')) == 2, 'AJAX submission succeeded.');
 
     // Submit the form with the non-Ajax "Save" button, leaving the title field
@@ -101,7 +101,7 @@ function testPreserveFormActionAfterAJAX() {
 
     // Ensure that the form contains two items in the multi-valued field, so we
     // know we're testing a form that was correctly retrieved from cache.
-    $this->assert(count($this->xpath('//form[contains(@id, "page-node-form")]//div[contains(@class, "form-item-field-ajax-test")]//input[@type="text"]')) == 2, 'Form retained its state from cache.');
+    $this->assert(count($this->xpath('//form[contains(@id, "page-node-add-form")]//div[contains(@class, "form-item-field-ajax-test")]//input[@type="text"]')) == 2, 'Form retained its state from cache.');
 
     // Ensure that the form's action is correct.
     $forms = $this->xpath('//form[contains(@class, "node-page-form")]');
diff --git a/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php b/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php
index a9d114a..ebef7bd 100644
--- a/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php
+++ b/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php
@@ -56,7 +56,7 @@ public static function create(ContainerInterface $container) {
    */
   public function testAdd($entity_type) {
     $entity = entity_create($entity_type, array());
-    $form = $this->entityFormBuilder()->getForm($entity);
+    $form = $this->entityFormBuilder()->getForm($entity, 'add');
     $form['#title'] = $this->t('Create an @type', array('@type' => $entity_type));
     return $form;
   }
@@ -74,7 +74,7 @@ public function testAdd($entity_type) {
    */
   public function testEdit(Request $request) {
     $entity = $request->attributes->get($request->attributes->get('_entity_type'));
-    $form = $this->entityFormBuilder()->getForm($entity);
+    $form = $this->entityFormBuilder()->getForm($entity, 'edit');
     $form['#title'] = $entity->label();
     return $form;
   }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
index 6831f1c..ce93e86 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
@@ -25,7 +25,8 @@
  *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php
index e235f6c..2f77d7b 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php
@@ -19,7 +19,8 @@
  *   controllers = {
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
  *   },
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php
index a6e02e1..b1ba4b5 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php
@@ -16,7 +16,8 @@
  *   controllers = {
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
  *   },
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php
index b5ba803..3289d5f 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php
@@ -21,7 +21,8 @@
  *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
index f4ee307..4bdbe36 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
@@ -20,7 +20,8 @@
  *   controllers = {
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
index 5f74c59..56a89b5 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
@@ -20,7 +20,8 @@
  *   controllers = {
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
index de9e47a..41addb8 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
@@ -18,7 +18,8 @@
  *   controllers = {
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
+ *       "add" = "Drupal\entity_test\Form\EntityTestAddForm",
+ *       "edit" = "Drupal\entity_test\Form\EntityTestEditForm",
  *     },
  *     "translation" = "Drupal\content_translation\ContentTranslationHandler"
  *   },
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php b/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php
index d68d4bc..b5eb45f 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\entity_test;
 
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides the entity_test delete form.
  */
-class EntityTestDeleteForm extends ContentEntityConfirmFormBase {
+class EntityTestDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -34,10 +34,11 @@ public function getQuestion() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $entity = $this->entity;
-    $entity->delete();
+
     drupal_set_message(t('%entity_type @id has been deleted.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId())));
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
diff --git a/core/modules/system/tests/modules/entity_test/src/Form/EntityTestAddForm.php b/core/modules/system/tests/modules/entity_test/src/Form/EntityTestAddForm.php
new file mode 100644
index 0000000..27ccfc9
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/src/Form/EntityTestAddForm.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config_test\Form\EntityTestAddForm.
+ */
+
+namespace Drupal\entity_test\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding "Test entity" entities.
+ */
+class EntityTestAddForm extends EntityTestFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $entity = $this->entity;
+
+    drupal_set_message($this->t('%entity_type @id has been created.', array(
+      '@id' => $entity->id(),
+      '%entity_type' => $entity->getEntityTypeId(),
+    )));
+  }
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/src/Form/EntityTestEditForm.php b/core/modules/system/tests/modules/entity_test/src/Form/EntityTestEditForm.php
new file mode 100644
index 0000000..add4317
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/src/Form/EntityTestEditForm.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config_test\Form\EntityTestEditForm.
+ */
+
+namespace Drupal\entity_test\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding "Test entity" entities.
+ */
+class EntityTestEditForm extends EntityTestFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $entity = $this->entity;
+
+    drupal_set_message($this->t('%entity_type @id has been updated.', array(
+      '@id' => $entity->id(),
+      '%entity_type' => $entity->getEntityTypeId(),
+    )));
+  }
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestForm.php b/core/modules/system/tests/modules/entity_test/src/Form/EntityTestFormBase.php
similarity index 79%
rename from core/modules/system/tests/modules/entity_test/src/EntityTestForm.php
rename to core/modules/system/tests/modules/entity_test/src/Form/EntityTestFormBase.php
index 9b0aaa3..5b10da4 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestForm.php
+++ b/core/modules/system/tests/modules/entity_test/src/Form/EntityTestFormBase.php
@@ -1,19 +1,19 @@
 <?php
 /**
  * @file
- * Definition of Drupal\entity_test\EntityTestForm.
+ * Definition of Drupal\entity_test\Form\EntityTestFormBase.
  */
 
-namespace Drupal\entity_test;
+namespace Drupal\entity_test\Form;
 
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
- * Form controller for the test entity edit forms.
+ * Provides a common base form for the "Test entity" entity.
  */
-class EntityTestForm extends ContentEntityForm {
+abstract class EntityTestFormBase extends ContentEntityForm {
 
   /**
    * {@inheritdoc}
@@ -80,17 +80,9 @@ public function submit(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $entity = $this->entity;
-    $is_new = $entity->isNew();
-    $entity->save();
+    parent::save($form, $form_state);
 
-    if ($is_new) {
-     $message = t('%entity_type @id has been created.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId()));
-    }
-    else {
-      $message = t('%entity_type @id has been updated.', array('@id' => $entity->id(), '%entity_type' => $entity->getEntityTypeId()));
-    }
-    drupal_set_message($message);
+    $entity = $this->entity;
 
     if ($entity->id()) {
       $entity_type = $entity->getEntityTypeId();
diff --git a/core/modules/system/tests/modules/form_test/src/Controller/FormTestController.php b/core/modules/system/tests/modules/form_test/src/Controller/FormTestController.php
index 600b1d9..a021892 100644
--- a/core/modules/system/tests/modules/form_test/src/Controller/FormTestController.php
+++ b/core/modules/system/tests/modules/form_test/src/Controller/FormTestController.php
@@ -30,8 +30,8 @@ public function twoFormInstances() {
     );
     $node1 = $this->entityManager()->getStorage('node')->create($values);
     $node2 = clone($node1);
-    $return['node_form_1'] = $this->entityFormBuilder()->getForm($node1);
-    $return['node_form_2'] = $this->entityFormBuilder()->getForm($node2);
+    $return['node_form_1'] = $this->entityFormBuilder()->getForm($node1, 'add');
+    $return['node_form_2'] = $this->entityFormBuilder()->getForm($node2, 'add');
     return $return;
   }
 
diff --git a/core/modules/taxonomy/src/Controller/TaxonomyController.php b/core/modules/taxonomy/src/Controller/TaxonomyController.php
index 0312a9d..d89c824 100644
--- a/core/modules/taxonomy/src/Controller/TaxonomyController.php
+++ b/core/modules/taxonomy/src/Controller/TaxonomyController.php
@@ -32,7 +32,7 @@ public function addForm(VocabularyInterface $taxonomy_vocabulary) {
     if ($this->moduleHandler()->moduleExists('language')) {
       $term->langcode = language_get_default_langcode('taxonomy_term', $taxonomy_vocabulary->id());
     }
-    return $this->entityFormBuilder()->getForm($term);
+    return $this->entityFormBuilder()->getForm($term, 'add');
   }
 
   /**
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index 597518e..489a3d3 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -25,7 +25,8 @@
  *     "view_builder" = "Drupal\taxonomy\TermViewBuilder",
  *     "access" = "Drupal\taxonomy\TermAccessControlHandler",
  *     "form" = {
- *       "default" = "Drupal\taxonomy\TermForm",
+ *       "add" = "Drupal\taxonomy\Form\TermAddForm",
+ *       "edit" = "Drupal\taxonomy\Form\TermEditForm",
  *       "delete" = "Drupal\taxonomy\Form\TermDeleteForm"
  *     },
  *     "translation" = "Drupal\taxonomy\TermTranslationHandler"
diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php
index 3927c34..d5c1e56 100644
--- a/core/modules/taxonomy/src/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/src/Entity/Vocabulary.php
@@ -21,7 +21,8 @@
  *     "storage" = "Drupal\taxonomy\VocabularyStorage",
  *     "list_builder" = "Drupal\taxonomy\VocabularyListBuilder",
  *     "form" = {
- *       "default" = "Drupal\taxonomy\VocabularyForm",
+ *       "add" = "Drupal\taxonomy\Form\VocabularyAddForm",
+ *       "edit" = "Drupal\taxonomy\Form\VocabularyEditForm",
  *       "reset" = "Drupal\taxonomy\Form\VocabularyResetForm",
  *       "delete" = "Drupal\taxonomy\Form\VocabularyDeleteForm"
  *     }
diff --git a/core/modules/taxonomy/src/Form/TermAddForm.php b/core/modules/taxonomy/src/Form/TermAddForm.php
new file mode 100644
index 0000000..60f2a9b
--- /dev/null
+++ b/core/modules/taxonomy/src/Form/TermAddForm.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\taxonomy\Form\TermAddForm.
+ */
+
+namespace Drupal\taxonomy\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form adding terms.
+ */
+class TermAddForm extends TermFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    /** @var \Drupal\taxonomy\TermInterface $term */
+    $term = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $term->urlInfo('edit-form'));
+
+    drupal_set_message($this->t('Created new term %term.', array('%term' => $term->getName())));
+    $this->logger('taxonomy')->notice('Created new term %term.', array(
+      '%term' => $term->getName(),
+      'link' => $edit_link
+    ));
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Form/TermDeleteForm.php b/core/modules/taxonomy/src/Form/TermDeleteForm.php
index 73b7321..c50a68a 100644
--- a/core/modules/taxonomy/src/Form/TermDeleteForm.php
+++ b/core/modules/taxonomy/src/Form/TermDeleteForm.php
@@ -11,12 +11,12 @@
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\ContentEntityConfirmFormBase;
+use Drupal\Core\Entity\ContentEntityDeleteFormBase;
 
 /**
  * Provides a deletion confirmation form for taxonomy term.
  */
-class TermDeleteForm extends ContentEntityConfirmFormBase {
+class TermDeleteForm extends ContentEntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -56,8 +56,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $storage = $this->entityManager->getStorage('taxonomy_vocabulary');
     $vocabulary = $storage->load($this->entity->bundle());
 
diff --git a/core/modules/taxonomy/src/Form/TermEditForm.php b/core/modules/taxonomy/src/Form/TermEditForm.php
new file mode 100644
index 0000000..5fbbd87
--- /dev/null
+++ b/core/modules/taxonomy/src/Form/TermEditForm.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\taxonomy\Form\TermEditForm.
+ */
+
+namespace Drupal\taxonomy\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form editing terms.
+ */
+class TermEditForm extends TermFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    /** @var \Drupal\taxonomy\TermInterface $term */
+    $term = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $term->urlInfo('edit-form'));
+
+    drupal_set_message($this->t('Updated term %term.', array('%term' => $term->getName())));
+    $this->logger('taxonomy')->notice('Updated term %term.', array(
+      '%term' => $term->getName(),
+      'link' => $edit_link,
+    ));
+  }
+
+}
diff --git a/core/modules/taxonomy/src/TermForm.php b/core/modules/taxonomy/src/Form/TermFormBase.php
similarity index 86%
rename from core/modules/taxonomy/src/TermForm.php
rename to core/modules/taxonomy/src/Form/TermFormBase.php
index 4a82e67..6ecfcae 100644
--- a/core/modules/taxonomy/src/TermForm.php
+++ b/core/modules/taxonomy/src/Form/TermFormBase.php
@@ -2,19 +2,19 @@
 
 /**
  * @file
- * Definition of Drupal\taxonomy\TermForm.
+ * Contains Drupal\taxonomy\Form\TermFormBase.
  */
 
-namespace Drupal\taxonomy;
+namespace Drupal\taxonomy\Form;
 
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 
 /**
- * Base for controller for taxonomy term edit forms.
+ * Provides a base form for term forms.
  */
-class TermForm extends ContentEntityForm {
+class TermFormBase extends ContentEntityForm {
 
   /**
    * {@inheritdoc}
@@ -132,18 +132,9 @@ public function buildEntity(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
-    $term = $this->entity;
+    parent::save($form, $form_state);
 
-    switch ($term->save()) {
-      case SAVED_NEW:
-        drupal_set_message($this->t('Created new term %term.', array('%term' => $term->getName())));
-        $this->logger('taxonomy')->notice('Created new term %term.', array('%term' => $term->getName(), 'link' => l($this->t('Edit'), 'taxonomy/term/' . $term->id() . '/edit')));
-        break;
-      case SAVED_UPDATED:
-        drupal_set_message($this->t('Updated term %term.', array('%term' => $term->getName())));
-        $this->logger('taxonomy')->notice('Updated term %term.', array('%term' => $term->getName(), 'link' => l($this->t('Edit'), 'taxonomy/term/' . $term->id() . '/edit')));
-        break;
-    }
+    $term = $this->entity;
 
     $current_parent_count = count($form_state->getValue('parent'));
     $previous_parent_count = count($form_state['taxonomy']['parent']);
diff --git a/core/modules/taxonomy/src/Form/VocabularyAddForm.php b/core/modules/taxonomy/src/Form/VocabularyAddForm.php
new file mode 100644
index 0000000..72d0b17
--- /dev/null
+++ b/core/modules/taxonomy/src/Form/VocabularyAddForm.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\taxonomy\Form\VocabularyAddForm.
+ */
+
+namespace Drupal\taxonomy\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding roles.
+ */
+class VocabularyAddForm extends VocabularyFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $vocabulary = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Created new vocabulary %name.', array('%name' => $vocabulary->name)));
+    $this->logger('taxonomy')->notice('Created new vocabulary %name.', array('%name' => $vocabulary->name, 'link' => $edit_link));
+    $form_state->setRedirectUrl($vocabulary->urlInfo('overview-form'));
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php b/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php
index e938b6e..b9115b3 100644
--- a/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php
+++ b/core/modules/taxonomy/src/Form/VocabularyDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\taxonomy\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a deletion confirmation form for taxonomy vocabulary.
  */
-class VocabularyDeleteForm extends EntityConfirmFormBase {
+class VocabularyDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -54,8 +54,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('Deleted vocabulary %name.', array('%name' => $this->entity->label())));
     $this->logger('taxonomy')->notice('Deleted vocabulary %name.', array('%name' => $this->entity->label()));
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/taxonomy/src/Form/VocabularyEditForm.php b/core/modules/taxonomy/src/Form/VocabularyEditForm.php
new file mode 100644
index 0000000..c19bd7c
--- /dev/null
+++ b/core/modules/taxonomy/src/Form/VocabularyEditForm.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\taxonomy\Form\VocabularyEditForm.
+ */
+
+namespace Drupal\taxonomy\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding roles.
+ */
+class VocabularyEditForm extends VocabularyFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $vocabulary = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Updated vocabulary %name.', array('%name' => $vocabulary->name)));
+    $this->logger('taxonomy')->notice('Updated vocabulary %name.', array('%name' => $vocabulary->name, 'link' => $edit_link));
+    $form_state->setRedirect('taxonomy.vocabulary_list');
+  }
+
+}
diff --git a/core/modules/taxonomy/src/VocabularyForm.php b/core/modules/taxonomy/src/Form/VocabularyFormBase.php
similarity index 83%
rename from core/modules/taxonomy/src/VocabularyForm.php
rename to core/modules/taxonomy/src/Form/VocabularyFormBase.php
index d34d3e2..82dbbfd 100644
--- a/core/modules/taxonomy/src/VocabularyForm.php
+++ b/core/modules/taxonomy/src/Form/VocabularyFormBase.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\taxonomy\VocabularyForm.
+ * Contains \Drupal\taxonomy\Form\VocabularyFormBase.
  */
 
-namespace Drupal\taxonomy;
+namespace Drupal\taxonomy\Form;
 
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
@@ -15,7 +15,7 @@
 /**
  * Base form for vocabulary edit forms.
  */
-class VocabularyForm extends EntityForm {
+abstract class VocabularyFormBase extends EntityForm {
 
   /**
    * {@inheritdoc}
@@ -131,27 +131,22 @@ public function languageConfigurationSubmit(array &$form, FormStateInterface $fo
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
+    parent::submit($form, $form_state);
+
     $vocabulary = $this->entity;
 
     // Prevent leading and trailing spaces in vocabulary names.
     $vocabulary->name = trim($vocabulary->name);
+  }
 
-    $status = $vocabulary->save();
-    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
-    switch ($status) {
-      case SAVED_NEW:
-        drupal_set_message($this->t('Created new vocabulary %name.', array('%name' => $vocabulary->name)));
-        $this->logger('taxonomy')->notice('Created new vocabulary %name.', array('%name' => $vocabulary->name, 'link' => $edit_link));
-        $form_state->setRedirectUrl($vocabulary->urlInfo('overview-form'));
-        break;
-
-      case SAVED_UPDATED:
-        drupal_set_message($this->t('Updated vocabulary %name.', array('%name' => $vocabulary->name)));
-        $this->logger('taxonomy')->notice('Updated vocabulary %name.', array('%name' => $vocabulary->name, 'link' => $edit_link));
-        $form_state->setRedirect('taxonomy.vocabulary_list');
-        break;
-    }
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $vocabulary = $this->entity;
 
     $form_state->setValue('vid', $vocabulary->id());
     $form_state['vid'] = $vocabulary->id();
diff --git a/core/modules/taxonomy/src/Tests/TermTest.php b/core/modules/taxonomy/src/Tests/TermTest.php
index 8886654..c81e567 100644
--- a/core/modules/taxonomy/src/Tests/TermTest.php
+++ b/core/modules/taxonomy/src/Tests/TermTest.php
@@ -352,7 +352,7 @@ function testTermInterface() {
       'description[0][value]' => $this->randomMachineName(100),
     );
     // Explicitly set the parents field to 'root', to ensure that
-    // TermForm::save() handles the invalid term ID correctly.
+    // TermFormBase::save() handles the invalid term ID correctly.
     $edit['parent[]'] = array(0);
 
     // Create the term to edit.
diff --git a/core/modules/taxonomy/taxonomy.routing.yml b/core/modules/taxonomy/taxonomy.routing.yml
index 1182589..cfaed65 100644
--- a/core/modules/taxonomy/taxonomy.routing.yml
+++ b/core/modules/taxonomy/taxonomy.routing.yml
@@ -17,7 +17,7 @@ taxonomy.term_add:
 taxonomy.term_edit:
   path: '/taxonomy/term/{taxonomy_term}/edit'
   defaults:
-    _entity_form: 'taxonomy_term.default'
+    _entity_form: 'taxonomy_term.edit'
     _title: 'Edit term'
   options:
     _admin_route: TRUE
@@ -37,7 +37,7 @@ taxonomy.term_delete:
 taxonomy.vocabulary_add:
   path: '/admin/structure/taxonomy/add'
   defaults:
-    _entity_form: 'taxonomy_vocabulary'
+    _entity_form: 'taxonomy_vocabulary.add'
     _title: 'Add vocabulary'
   requirements:
     _entity_create_access: 'taxonomy_vocabulary'
@@ -45,7 +45,7 @@ taxonomy.vocabulary_add:
 taxonomy.vocabulary_edit:
   path: '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}'
   defaults:
-    _entity_form: 'taxonomy_vocabulary.default'
+    _entity_form: 'taxonomy_vocabulary.edit'
     _title_callback: '\Drupal\taxonomy\Controller\TaxonomyController::vocabularyTitle'
   requirements:
     _entity_access: 'taxonomy_vocabulary.update'
diff --git a/core/modules/user/src/Entity/Role.php b/core/modules/user/src/Entity/Role.php
index e5a6f8b..96422e2 100644
--- a/core/modules/user/src/Entity/Role.php
+++ b/core/modules/user/src/Entity/Role.php
@@ -22,7 +22,8 @@
  *     "access" = "Drupal\user\RoleAccessControlHandler",
  *     "list_builder" = "Drupal\user\RoleListBuilder",
  *     "form" = {
- *       "default" = "Drupal\user\RoleForm",
+ *       "add" = "Drupal\user\Form\RoleAddForm",
+ *       "edit" = "Drupal\user\Form\RoleEditForm",
  *       "delete" = "Drupal\user\Form\UserRoleDelete"
  *     }
  *   },
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index afaa840..e4671b9 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -20,6 +20,10 @@
  * The base table name here is plural, despite Drupal table naming standards,
  * because "user" is a reserved word in many databases.
  *
+ * @todo The 'profile' form operation is duplicated by the 'add' and 'edit' form
+ *   operations because Content Translation module requires the latter form
+ *   operations to exist.
+ *
  * @ContentEntityType(
  *   id = "user",
  *   label = @Translation("User"),
@@ -29,9 +33,11 @@
  *     "list_builder" = "Drupal\user\UserListBuilder",
  *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
  *     "form" = {
- *       "default" = "Drupal\user\ProfileForm",
+ *       "register" = "Drupal\user\RegisterForm",
+ *       "profile" = "Drupal\user\ProfileForm",
+ *       "add" = "Drupal\user\ProfileForm",
+ *       "edit" = "Drupal\user\ProfileForm",
  *       "cancel" = "Drupal\user\Form\UserCancelForm",
- *       "register" = "Drupal\user\RegisterForm"
  *     },
  *     "translation" = "Drupal\user\ProfileTranslationHandler"
  *   },
diff --git a/core/modules/user/src/Form/RoleAddForm.php b/core/modules/user/src/Form/RoleAddForm.php
new file mode 100644
index 0000000..ad78411
--- /dev/null
+++ b/core/modules/user/src/Form/RoleAddForm.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Form\RoleAddForm.
+ */
+
+namespace Drupal\user\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding roles.
+ */
+class RoleAddForm extends RoleFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $entity = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Role %label has been added.', array('%label' => $entity->label())));
+    $this->logger('user')->notice('Role %label has been added.', array('%label' => $entity->label(), 'link' => $edit_link));
+  }
+
+}
diff --git a/core/modules/user/src/Form/RoleEditForm.php b/core/modules/user/src/Form/RoleEditForm.php
new file mode 100644
index 0000000..f3fe806
--- /dev/null
+++ b/core/modules/user/src/Form/RoleEditForm.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Form\RoleEditForm.
+ */
+
+namespace Drupal\user\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a form for adding roles.
+ */
+class RoleEditForm extends RoleFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $entity = $this->entity;
+    $edit_link = $this->getLinkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
+
+    drupal_set_message($this->t('Role %label has been updated.', array('%label' => $entity->label())));
+    $this->logger('user')->notice('Role %label has been updated.', array('%label' => $entity->label(), 'link' => $edit_link));
+  }
+
+}
diff --git a/core/modules/user/src/RoleForm.php b/core/modules/user/src/Form/RoleFormBase.php
similarity index 63%
rename from core/modules/user/src/RoleForm.php
rename to core/modules/user/src/Form/RoleFormBase.php
index 55e0ccd..ef683da 100644
--- a/core/modules/user/src/RoleForm.php
+++ b/core/modules/user/src/Form/RoleFormBase.php
@@ -2,19 +2,19 @@
 
 /**
  * @file
- * Contains \Drupal\user\RoleForm.
+ * Contains \Drupal\user\Form\RoleFormBase.
  */
 
-namespace Drupal\user;
+namespace Drupal\user\Form;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
- * Form controller for the role entity edit forms.
+ * Provides a common base form for role forms.
  */
-class RoleForm extends EntityForm {
+class RoleFormBase extends EntityForm {
 
   /**
    * {@inheritdoc}
@@ -52,22 +52,21 @@ public function form(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  public function submit(array $form, FormStateInterface $form_state) {
+    parent::submit($form, $form_state);
+
     $entity = $this->entity;
 
     // Prevent leading and trailing spaces in role names.
     $entity->set('label', trim($entity->label()));
-    $status = $entity->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
-    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message($this->t('Role %label has been updated.', array('%label' => $entity->label())));
-      $this->logger('user')->notice('Role %label has been updated.', array('%label' => $entity->label(), 'link' => $edit_link));
-    }
-    else {
-      drupal_set_message($this->t('Role %label has been added.', array('%label' => $entity->label())));
-      $this->logger('user')->notice('Role %label has been added.', array('%label' => $entity->label(), 'link' => $edit_link));
-    }
     $form_state->setRedirect('user.role_list');
   }
 
diff --git a/core/modules/user/src/Form/UserCancelForm.php b/core/modules/user/src/Form/UserCancelForm.php
index 2dcef4e..4349660 100644
--- a/core/modules/user/src/Form/UserCancelForm.php
+++ b/core/modules/user/src/Form/UserCancelForm.php
@@ -118,6 +118,17 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
+  public function actions(array $form, FormStateInterface $form_state) {
+    $actions = parent::actions($form, $form_state);
+    // Separate 'submit' and 'save' stages do not apply for this form.
+    // @see \Drupal\Core\Entity\EntityForm::actions()
+    $actions['submit']['#submit'] = array(array($this, 'submit'));
+    return $actions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function submit(array $form, FormStateInterface $form_state) {
     // Cancel account immediately, if the current user has administrative
     // privileges, no confirmation mail shall be sent, and the user does not
diff --git a/core/modules/user/src/Form/UserRoleDelete.php b/core/modules/user/src/Form/UserRoleDelete.php
index bdd4f08..eba9c88 100644
--- a/core/modules/user/src/Form/UserRoleDelete.php
+++ b/core/modules/user/src/Form/UserRoleDelete.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\user\Form;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a deletion confirmation form for Role entity.
  */
-class UserRoleDelete extends EntityConfirmFormBase {
+class UserRoleDelete extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -41,7 +41,8 @@ public function getConfirmText() {
    * {@inheritdoc}
    */
   public function submit(array $form, FormStateInterface $form_state) {
-    $this->entity->delete();
+    parent::save($form, $form_state);
+
     $this->logger('user')->notice('Role %name has been deleted.', array('%name' => $this->entity->label()));
     drupal_set_message($this->t('Role %name has been deleted.', array('%name' => $this->entity->label())));
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/user/src/ProfileForm.php b/core/modules/user/src/ProfileForm.php
index 4f0f088..3f97e8f 100644
--- a/core/modules/user/src/ProfileForm.php
+++ b/core/modules/user/src/ProfileForm.php
@@ -47,8 +47,9 @@ protected function actions(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $account = $this->entity;
-    $account->save();
     $form_state->setValue('uid', $account->id());
 
     drupal_set_message($this->t('The changes have been saved.'));
diff --git a/core/modules/user/src/RegisterForm.php b/core/modules/user/src/RegisterForm.php
index 2a9cb41..a4d00ea 100644
--- a/core/modules/user/src/RegisterForm.php
+++ b/core/modules/user/src/RegisterForm.php
@@ -98,15 +98,13 @@ public function submit(array $form, FormStateInterface $form_state) {
    * Overrides Drupal\Core\Entity\EntityForm::submit().
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $account = $this->entity;
     $pass = $account->getPassword();
     $admin = $form_state->getValue('administer_users');
     $notify = !$form_state->isValueEmpty('notify');
 
-    // Save has no return value so this cannot be tested.
-    // Assume save has gone through correctly.
-    $account->save();
-
     $form_state['user'] = $account;
     $form_state->setValue('uid', $account->id());
 
diff --git a/core/modules/user/src/Tests/UserAccountFormFieldsTest.php b/core/modules/user/src/Tests/UserAccountFormFieldsTest.php
index 492218f..41d8545 100644
--- a/core/modules/user/src/Tests/UserAccountFormFieldsTest.php
+++ b/core/modules/user/src/Tests/UserAccountFormFieldsTest.php
@@ -79,7 +79,7 @@ function testUserEditForm() {
     // Install default configuration; required for AccountFormController.
     $this->installConfig(array('user'));
 
-    $form = $this->buildAccountForm('default');
+    $form = $this->buildAccountForm('profile');
 
     // Verify name and pass field order.
     $this->assertFieldOrder($form['account']);
@@ -138,9 +138,6 @@ protected function buildAccountForm($operation) {
     $entity = $this->container->get('entity.manager')
       ->getStorage($entity_type)
       ->create($fields);
-    $form_object = $this->container->get('entity.manager')
-      ->getFormObject($entity_type, $operation)
-      ->setEntity($entity);
 
     // @see EntityFormBuilder::getForm()
     return $this->container->get('entity.form_builder')->getForm($entity, $operation);
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index 3363394..2ee021a 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -94,7 +94,7 @@ user.role_list:
 user.role_add:
   path: '/admin/people/roles/add'
   defaults:
-    _entity_form: user_role.default
+    _entity_form: user_role.add
     _title: 'Add role'
   requirements:
     _permission: 'administer permissions'
@@ -102,7 +102,7 @@ user.role_add:
 entity.user_role.edit_form:
   path: '/admin/people/roles/manage/{user_role}'
   defaults:
-    _entity_form: user_role.default
+    _entity_form: user_role.edit
     _title: 'Edit role'
   requirements:
     _entity_access: user_role.update
@@ -154,7 +154,7 @@ user.login:
 user.edit:
   path: '/user/{user}/edit'
   defaults:
-    _entity_form: 'user.default'
+    _entity_form: 'user.profile'
     _title_callback: 'Drupal\user\Controller\UserController::userTitle'
   options:
     _admin_route: TRUE
diff --git a/core/modules/views_ui/src/ViewAddForm.php b/core/modules/views_ui/src/ViewAddForm.php
index 8717ff9..f83073f 100644
--- a/core/modules/views_ui/src/ViewAddForm.php
+++ b/core/modules/views_ui/src/ViewAddForm.php
@@ -185,7 +185,7 @@ public function submit(array $form, FormStateInterface $form_state) {
     try {
       /** @var $wizard \Drupal\views\Plugin\views\wizard\WizardInterface */
       $wizard = $form_state['wizard_instance'];
-      $view = $wizard->createView($form, $form_state);
+      $this->entity = $wizard->createView($form, $form_state);
     }
     // @todo Figure out whether it really makes sense to throw and catch exceptions on the wizard.
     catch (WizardException $e) {
@@ -193,9 +193,15 @@ public function submit(array $form, FormStateInterface $form_state) {
       $form_state->setRedirect('views_ui.list');
       return;
     }
-    $view->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
-    $form_state->setRedirectUrl($view->urlInfo('edit-form'));
+    $form_state->setRedirectUrl($this->entity->urlInfo('edit-form'));
   }
 
   /**
diff --git a/core/modules/views_ui/src/ViewDeleteForm.php b/core/modules/views_ui/src/ViewDeleteForm.php
index 1acc4b8..4e7e0b0 100644
--- a/core/modules/views_ui/src/ViewDeleteForm.php
+++ b/core/modules/views_ui/src/ViewDeleteForm.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\views_ui;
 
-use Drupal\Core\Entity\EntityConfirmFormBase;
+use Drupal\Core\Entity\EntityDeleteFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 
 /**
  * Provides a delete form for a view.
  */
-class ViewDeleteForm extends EntityConfirmFormBase {
+class ViewDeleteForm extends EntityDeleteFormBase {
 
   /**
    * {@inheritdoc}
@@ -40,10 +40,9 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
-    parent::submit($form, $form_state);
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
-    $this->entity->delete();
     drupal_set_message($this->t('View %name deleted',array('%name' => $this->entity->label())));
 
     $form_state->setRedirectUrl($this->getCancelUrl());
diff --git a/core/modules/views_ui/src/ViewDuplicateForm.php b/core/modules/views_ui/src/ViewDuplicateForm.php
index e817e36..3a478c2 100644
--- a/core/modules/views_ui/src/ViewDuplicateForm.php
+++ b/core/modules/views_ui/src/ViewDuplicateForm.php
@@ -60,6 +60,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
       '#value' => $this->t('Duplicate'),
       '#submit' => array(
         array($this, 'submit'),
+        array($this, 'save'),
       ),
     );
     return $actions;
@@ -72,11 +73,18 @@ public function submit(array $form, FormStateInterface $form_state) {
     $original = parent::submit($form, $form_state);
     $this->entity = $original->createDuplicate();
     $this->entity->set('id', $form_state->getValue('id'));
-    $this->entity->save();
+
+    return $this->entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
     // Redirect the user to the view admin form.
     $form_state->setRedirectUrl($this->entity->urlInfo('edit-form'));
-    return $this->entity;
   }
 
 }
diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php
index 6d42b52..4f100ff 100644
--- a/core/modules/views_ui/src/ViewEditForm.php
+++ b/core/modules/views_ui/src/ViewEditForm.php
@@ -305,8 +305,13 @@ public function submit(array $form, FormStateInterface $form_state) {
       }
     }
     $view->set('display', $displays);
+  }
 
-    // @todo: Revisit this when http://drupal.org/node/1668866 is in.
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    $view = $this->entity;
     $query = $this->requestStack->getCurrentRequest()->query;
     $destination = $query->get('destination');
 
@@ -332,7 +337,8 @@ public function submit(array $form, FormStateInterface $form_state) {
       $form_state->setRedirectUrl(Url::createFromPath($destination));
     }
 
-    $view->save();
+    parent::save($form, $form_state);
+
     drupal_set_message($this->t('The view %name has been saved.', array('%name' => $view->label())));
 
     // Remove this view from cache so we can edit it properly.
