diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDeleteFormBase.php b/core/lib/Drupal/Core/Entity/ContentEntityDeleteFormBase.php
new file mode 100644
index 0000000..21e5898
--- /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..5ec14b9
--- /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..b0a5e01 100644
--- a/core/modules/aggregator/src/FeedForm.php
+++ b/core/modules/aggregator/src/FeedForm.php
@@ -62,9 +62,11 @@ public function validate(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
     $feed = $this->entity;
     $insert = (bool) $feed->id();
-    $feed->save();
+    // @ŧ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..ade344f 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 c825620..6720ad4 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 17a358e..399a882 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..71780d1
--- /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..8596c93
--- /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..dc1428d
--- /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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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..3fb4304
--- /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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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 70%
rename from core/modules/block_content/src/BlockContentTypeForm.php
rename to core/modules/block_content/src/Form/BlockContentTypeFormBase.php
index 0675657..8e31856 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}
@@ -88,20 +88,8 @@ 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));
-    }
+  public function save(array $form, FormStateInterface &$form_state) {
+    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 8530fab..daaabb0 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/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/CommentTypeAddForm.php b/core/modules/comment/src/Form/CommentTypeAddForm.php
new file mode 100644
index 0000000..66ce52a
--- /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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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..dd901a6
--- /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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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 78%
rename from core/modules/comment/src/CommentTypeForm.php
rename to core/modules/comment/src/Form/CommentTypeFormBase.php
index 418aea1..1ef62a9 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.
@@ -133,19 +133,8 @@ 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));
-    }
+  public function save(array $form, FormStateInterface &$form_state) {
+    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/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..a26814b
--- /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..ae833e1
--- /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 72%
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..a8a857e 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}
@@ -70,16 +70,8 @@ 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())));
-    }
+  public function save(array $form, FormStateInterface &$form_state) {
+    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..23ec3fc
--- /dev/null
+++ b/core/modules/contact/src/Form/CategoryAddForm.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Form\CategoryAddForm.
+ */
+
+namespace Drupal\contact\Form;
+
+use Drupal\contact\CategoryFormBase;
+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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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..ceedc0f
--- /dev/null
+++ b/core/modules/contact/src/Form/CategoryEditForm.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Form\CategoryEditForm.
+ */
+
+namespace Drupal\contact\Form;
+
+use Drupal\contact\CategoryFormBase;
+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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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 81%
rename from core/modules/contact/src/CategoryForm.php
rename to core/modules/contact/src/Form/CategoryFormBase.php
index e6defb1..8267363 100644
--- a/core/modules/contact/src/CategoryForm.php
+++ b/core/modules/contact/src/Form/CategoryFormBase.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\contact\CategoryForm.
+ * Contains \Drupal\contact\Form\CategoryFormBase.
  */
 
 namespace Drupal\contact;
@@ -12,9 +12,9 @@
 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/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 11b39e5..2cef86e 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..b6cdbdf 100644
--- a/core/modules/field/src/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/src/Tests/FieldAttachOtherTest.php
@@ -295,7 +295,7 @@ function testEntityFormDisplayExtractFormValues() {
     $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $this->fieldTestData->instance->bundle));
 
     // Build the form for all fields.
-    $display = entity_get_form_display($entity_type, $this->fieldTestData->instance->bundle, 'default');
+    $display = entity_get_form_display($entity_type, $this->fieldTestData->instance->bundle, 'add');
     $form = array();
     $form_state = new FormState();
     $display->buildForm($entity_init, $form, $form_state);
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..d735f41 100644
--- a/core/modules/forum/src/Form/ForumForm.php
+++ b/core/modules/forum/src/Form/ForumForm.php
@@ -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 e1ff08a..888dfb2 100644
--- a/core/modules/image/src/Form/ImageStyleEditForm.php
+++ b/core/modules/image/src/Form/ImageStyleEditForm.php
@@ -213,13 +213,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/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/MenuLinkContentForm.php b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
index 35f6d8e..8537ce3 100644
--- a/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
+++ b/core/modules/menu_link_content/src/Form/MenuLinkContentForm.php
@@ -32,6 +32,8 @@
  * 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.
+ *
+ * @todo Split this form into dedicated add and edit forms.
  */
 class MenuLinkContentForm extends ContentEntityForm implements MenuLinkFormInterface {
 
diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module
index 83528b5..7143f75 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..60794af
--- /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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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/MenuEditForm.php b/core/modules/menu_ui/src/Form/MenuEditForm.php
new file mode 100644
index 0000000..f53360f
--- /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->l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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 302a9e2..75e3356 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.
@@ -175,23 +175,13 @@ public function menuNameExists($value) {
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
+    parent::save($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));
-    }
-
     $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 7f3c8f6..0121e8c 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -404,7 +404,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 e40cf7e..22e146c 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 b9d5a53..a2cdc5f 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\NodeAddForm",
+ *       "edit" = "Drupal\node\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 91ce4f7..cde847e 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..21f4a0f
--- /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->nodeTypeStorage->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..93dd5fc
--- /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->nodeTypeStorage->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 94%
rename from core/modules/node/src/NodeForm.php
rename to core/modules/node/src/Form/NodeFormBase.php
index 0965b16..439b90a 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/Form/NodeFormBase.php
@@ -2,22 +2,31 @@
 
 /**
  * @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 {
+
+  /**
+   * The node type storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $nodeTypeStorage;
 
   /**
    * Default settings for this content/node type.
@@ -27,6 +36,25 @@ class NodeForm extends ContentEntityForm {
   protected $settings;
 
   /**
+   * Constructs a NodeFormBase.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageInteface
+   *   The node type storage.
+   */
+  public function __construct(EntityStorageInterface $node_type_storage) {
+    $this->nodeTypeStorage = $node_type_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity.manager')->getStorage('node_type')
+    );
+  }
+
+  /**
    * {@inheritdoc}
    */
   protected function prepareEntity() {
@@ -429,21 +457,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..6639d67
--- /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..b80e72a
--- /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/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 180c75a..7a21ca9 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/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 4e94184..3ff0c17 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 e9e7123..0f6887f 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 c5227e4..5653058 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 477b651..1295581 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 9424241..c054672 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 dbe4a20..4fb1170 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..2c75426
--- /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..730429e
--- /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 77%
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..ab29d0f 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}
@@ -79,18 +79,10 @@ 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();
+  public function save(array $form, FormStateInterface &$form_state) {
+    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/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/TermDeleteForm.php b/core/modules/taxonomy/src/Form/TermDeleteForm.php
index 73b7321..2175dfe 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/VocabularyAddForm.php b/core/modules/taxonomy/src/Form/VocabularyAddForm.php
new file mode 100644
index 0000000..9bfd978
--- /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 = \Drupal::l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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..4f85359
--- /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 = \Drupal::l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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 94%
rename from core/modules/taxonomy/src/VocabularyForm.php
rename to core/modules/taxonomy/src/Form/VocabularyFormBase.php
index d34d3e2..86fdde3 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,13 +131,23 @@ 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);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
+
+    $vocabulary = $this->entity;
 
-    $status = $vocabulary->save();
     $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
     switch ($status) {
       case SAVED_NEW:
diff --git a/core/modules/taxonomy/src/TermForm.php b/core/modules/taxonomy/src/TermForm.php
index 4a82e67..610d155 100644
--- a/core/modules/taxonomy/src/TermForm.php
+++ b/core/modules/taxonomy/src/TermForm.php
@@ -134,6 +134,7 @@ public function buildEntity(array $form, FormStateInterface $form_state) {
   public function save(array $form, FormStateInterface $form_state) {
     $term = $this->entity;
 
+    // @todo Split this into dedicated add and edit forms.
     switch ($term->save()) {
       case SAVED_NEW:
         drupal_set_message($this->t('Created new term %term.', array('%term' => $term->getName())));
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/Form/RoleAddForm.php b/core/modules/user/src/Form/RoleAddForm.php
new file mode 100644
index 0000000..1b01ee1
--- /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 = \Drupal::l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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..40984c6
--- /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 = \Drupal::l($this->t('Edit'), $this->entity->urlInfo()->getRouteName());
+
+    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/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..bdb2d37 100644
--- a/core/modules/user/src/ProfileForm.php
+++ b/core/modules/user/src/ProfileForm.php
@@ -46,9 +46,10 @@ protected function actions(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  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..44b31f9 100644
--- a/core/modules/user/src/RegisterForm.php
+++ b/core/modules/user/src/RegisterForm.php
@@ -97,16 +97,14 @@ public function submit(array $form, FormStateInterface $form_state) {
   /**
    * Overrides Drupal\Core\Entity\EntityForm::submit().
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  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/views_ui/src/ViewAddForm.php b/core/modules/views_ui/src/ViewAddForm.php
index 8717ff9..b7c2a1e 100644
--- a/core/modules/views_ui/src/ViewAddForm.php
+++ b/core/modules/views_ui/src/ViewAddForm.php
@@ -181,7 +181,7 @@ public function validate(array $form, FormStateInterface $form_state) {
   /**
    * {@inheritdoc}
    */
-  public function submit(array $form, FormStateInterface $form_state) {
+  public function save(array $form, FormStateInterface $form_state) {
     try {
       /** @var $wizard \Drupal\views\Plugin\views\wizard\WizardInterface */
       $wizard = $form_state['wizard_instance'];
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..2791adb 100644
--- a/core/modules/views_ui/src/ViewEditForm.php
+++ b/core/modules/views_ui/src/ViewEditForm.php
@@ -305,8 +305,14 @@ public function submit(array $form, FormStateInterface $form_state) {
       }
     }
     $view->set('display', $displays);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    parent::save($form, $form_state);
 
-    // @todo: Revisit this when http://drupal.org/node/1668866 is in.
     $query = $this->requestStack->getCurrentRequest()->query;
     $destination = $query->get('destination');
 
@@ -332,7 +338,6 @@ public function submit(array $form, FormStateInterface $form_state) {
       $form_state->setRedirectUrl(Url::createFromPath($destination));
     }
 
-    $view->save();
     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.
