diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index ce12db5..a1ac688 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -203,6 +203,15 @@ drupal.dropbutton:
     - core/drupalSettings
     - core/jquery.once
 
+drupal.entity:
+  version: VERSION
+  js:
+    misc/entity.js: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
+    - core/drupal.form
+
 drupal.form:
   version: VERSION
   js:
diff --git a/core/lib/Drupal/Core/Entity/Form/RevisionableContentEntityForm.php b/core/lib/Drupal/Core/Entity/Form/RevisionableContentEntityForm.php
new file mode 100644
index 0000000..54c6651
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Form/RevisionableContentEntityForm.php
@@ -0,0 +1,199 @@
+<?php
+
+namespace Drupal\Core\Entity\Form;
+
+use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\RevisionableEntityBundleInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Extends the base entity form with revision support in the UI.
+ */
+class RevisionableContentEntityForm extends ContentEntityForm {
+
+  /**
+   * The entity being used by this form.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface|\Drupal\Core\Entity\RevisionableInterface|\Drupal\Core\Entity\EntityRevisionLogInterface
+   */
+  protected $entity;
+
+  /**
+   * The entity type bundle info service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $entityTypeBundleInfo;
+
+  /**
+   * Constructs a ContentEntityForm object.
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+   *   The entity type bundle info service.
+   */
+  public function __construct(EntityManagerInterface $entity_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
+    parent::__construct($entity_manager);
+
+    $this->entityTypeBundleInfo = $entity_type_bundle_info;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity.manager'),
+      $container->get('entity_type.bundle.info')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function prepareEntity() {
+    parent::prepareEntity();
+
+    // Hide the current revision log message in UI.
+    if (!$this->entity->isNew()) {
+      $this->entity->setRevisionLogMessage(NULL);
+    }
+  }
+
+  /**
+   * Returns the bundle entity of the entity, or NULL if there is none.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface|null
+   *   The bundle entity.
+   */
+  protected function getBundleEntity() {
+    if ($bundle_entity_type = $this->entity->getEntityType()->getBundleEntityType()) {
+      return $this->entityTypeManager->getStorage($bundle_entity_type)->load($this->entity->bundle());
+    }
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, FormStateInterface $form_state) {
+
+    // Advanced tab must be the first, because other fields rely on that.
+    $form['advanced'] = [
+      '#type' => 'vertical_tabs',
+      '#weight' => 99,
+    ];
+
+    $form = parent::form($form, $form_state);
+
+    $entity_type = $this->entity->getEntityType();
+    $account = $this->currentUser();
+
+    if ($this->operation == 'edit') {
+
+      $bundleInfo = $this->entityTypeBundleInfo->getBundleInfo($entity_type->id());
+      if ($bundleInfo[$this->entity->bundle()]) {
+        $bundleLabel = $bundleInfo[$this->entity->bundle()]['label'];
+        $form['#title'] = $this->t('<em>Edit @bundle_label</em> @label', [
+          '@bundle_label' => $bundleLabel,
+          '@label' => $this->entity->label(),
+        ]);
+      }
+      else {
+        $form['#title'] = $this->t('<em>Edit</em> @label', [
+          '@label' => $this->entity->label(),
+        ]);
+      }
+    }
+
+    $new_revision_default = FALSE;
+    $bundle_entity = $this->getBundleEntity();
+    if ($bundle_entity instanceof RevisionableEntityBundleInterface) {
+      // Always use the default revision setting.
+      $new_revision_default = $bundle_entity->shouldCreateNewRevision();
+    }
+
+    // Add a log field if the "Create new revision" option is checked, or if the
+    // current user has the ability to check that option.
+    $form['revision_information'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Revision information'),
+      // Open by default when "Create new revision" is checked.
+      '#open' => $new_revision_default,
+      '#group' => 'advanced',
+      '#weight' => 20,
+      '#access' => $new_revision_default || ($entity_type->get('admin_permission')) && $account->hasPermission($entity_type->get('admin_permission')),
+      '#optional' => TRUE,
+      '#attributes' => [
+        'class' => ['entity-content-form-revision-information'],
+      ],
+      '#attached' => [
+        'library' => ['core/drupal.entity'],
+      ],
+    ];
+
+    $form['revision'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Create new revision'),
+      '#default_value' => $new_revision_default,
+      '#access' => !$this->entity->isNew() && ($entity_type->get('admin_permission') || $account->hasPermission($entity_type->get('admin_permission'))),
+      '#group' => 'revision_information',
+    ];
+
+    // Check the revision log checkbox when the log textarea is filled in.
+    // This must not happen if "Create new revision" is enabled by default,
+    // since the state would auto-disable the checkbox otherwise.
+    if (!$this->entity->isNewRevision()) {
+      $form['revision']['#states'] = [
+        'checked' => [
+          'textarea[name="revision_log[0][value]"]' => ['empty' => FALSE],
+        ],
+      ];
+    }
+
+    if (isset($form['revision_log'])) {
+      $form['revision_log']['#group'] = 'revision_information';
+    }
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    // Save as a new revision if requested to do so.
+    if (!$form_state->isValueEmpty('revision')) {
+      $this->entity->setNewRevision();
+    }
+
+    $insert = $this->entity->isNew();
+    $this->entity->save();
+
+    $context = ['@type' => $this->entity->bundle(), '%info' => $this->entity->label()];
+    $logger = $this->logger($this->entity->getEntityTypeId());
+    $bundle_entity = $this->getBundleEntity();
+    $t_args = ['@type' => $bundle_entity ? $bundle_entity->label() : $this->entity->getEntityType()->getLabel(), '%label' => $this->entity->label()];
+
+    if ($insert) {
+      $logger->notice('@type: added %info.', $context);
+      drupal_set_message($this->t('@type %label has been created.', $t_args));
+    }
+    else {
+      $logger->notice('@type: updated %info.', $context);
+      drupal_set_message($this->t('@type %label has been updated.', $t_args));
+    }
+
+    if ($this->entity->getEntityType()->hasLinkTemplate('collection')) {
+      $form_state->setRedirectUrl($this->entity->toUrl('collection'));
+    }
+    else {
+      $form_state->setRedirectUrl($this->entity->toUrl('canonical'));
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php b/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php
new file mode 100644
index 0000000..caf44f2
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/RevisionableEntityBundleInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface defining a revisionable entity bundle.
+ */
+interface RevisionableEntityBundleInterface extends ConfigEntityInterface {
+
+  /**
+   * Gets whether a new revision should be created by default.
+   *
+   * @return bool
+   *   TRUE if a new revision should be created by default.
+   */
+  public function shouldCreateNewRevision();
+
+}
diff --git a/core/modules/block_content/js/block_content.js b/core/misc/entity.js
similarity index 82%
rename from core/modules/block_content/js/block_content.js
rename to core/misc/entity.js
index bbc0533..f86c416 100644
--- a/core/modules/block_content/js/block_content.js
+++ b/core/misc/entity.js
@@ -8,20 +8,20 @@
   'use strict';
 
   /**
-   * Sets summaries about revision and translation of block content.
+   * Sets summaries about revision and translation of entities.
    *
    * @type {Drupal~behavior}
    *
    * @prop {Drupal~behaviorAttach} attach
-   *   Attaches summary behaviour block content form tabs.
+   *   Attaches summary behaviour entity form tabs.
    *
    *   Specifically, it updates summaries to the revision information and the
    *   translation options.
    */
-  Drupal.behaviors.blockContentDetailsSummaries = {
+  Drupal.behaviors.entityContentDetailsSummaries = {
     attach: function (context) {
       var $context = $(context);
-      $context.find('.block-content-form-revision-information').drupalSetSummary(function (context) {
+      $context.find('.entity-content-form-revision-information').drupalSetSummary(function (context) {
         var $revisionContext = $(context);
         var revisionCheckbox = $revisionContext.find('.js-form-item-revision input');
 
@@ -36,7 +36,7 @@
         return Drupal.t('No revision');
       });
 
-      $context.find('fieldset.block-content-translation-options').drupalSetSummary(function (context) {
+      $context.find('details.entity-translation-options').drupalSetSummary(function (context) {
         var $translationContext = $(context);
         var translate;
         var $checkbox = $translationContext.find('.js-form-item-translation-translate input');
diff --git a/core/modules/block_content/block_content.libraries.yml b/core/modules/block_content/block_content.libraries.yml
deleted file mode 100644
index 5a1b5b6..0000000
--- a/core/modules/block_content/block_content.libraries.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-drupal.block_content:
-  version: VERSION
-  js:
-    js/block_content.js: {}
-  dependencies:
-    - core/jquery
-    - core/drupal
-    - core/drupal.form
diff --git a/core/modules/block_content/src/BlockContentForm.php b/core/modules/block_content/src/BlockContentForm.php
index 8815f56..6fc6569 100644
--- a/core/modules/block_content/src/BlockContentForm.php
+++ b/core/modules/block_content/src/BlockContentForm.php
@@ -3,38 +3,13 @@
 namespace Drupal\block_content;
 
 use Drupal\Component\Utility\Html;
-use Drupal\Core\Entity\ContentEntityForm;
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\Form\RevisionableContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Language\LanguageManagerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Form handler for the custom block edit forms.
  */
-class BlockContentForm extends ContentEntityForm {
-
-  /**
-   * The custom block storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $blockContentStorage;
-
-  /**
-   * The custom block type storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $blockContentTypeStorage;
-
-  /**
-   * The language manager.
-   *
-   * @var \Drupal\Core\Language\LanguageManagerInterface
-   */
-  protected $languageManager;
+class BlockContentForm extends RevisionableContentEntityForm {
 
   /**
    * The block content entity.
@@ -44,121 +19,22 @@ class BlockContentForm extends ContentEntityForm {
   protected $entity;
 
   /**
-   * Constructs a BlockContentForm object.
-   *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Entity\EntityStorageInterface $block_content_storage
-   *   The custom block storage.
-   * @param \Drupal\Core\Entity\EntityStorageInterface $block_content_type_storage
-   *   The custom block type storage.
-   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
-   *   The language manager.
-   */
-  public function __construct(EntityManagerInterface $entity_manager, EntityStorageInterface $block_content_storage, EntityStorageInterface $block_content_type_storage, LanguageManagerInterface $language_manager) {
-    parent::__construct($entity_manager);
-    $this->blockContentStorage = $block_content_storage;
-    $this->blockContentTypeStorage = $block_content_type_storage;
-    $this->languageManager = $language_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    $entity_manager = $container->get('entity.manager');
-    return new static(
-      $entity_manager,
-      $entity_manager->getStorage('block_content'),
-      $entity_manager->getStorage('block_content_type'),
-      $container->get('language_manager')
-    );
-  }
-
-  /**
-   * Overrides \Drupal\Core\Entity\EntityForm::prepareEntity().
-   *
-   * Prepares the custom block object.
-   *
-   * Fills in a few default values, and then invokes
-   * hook_block_content_prepare() on all modules.
-   */
-  protected function prepareEntity() {
-    $block = $this->entity;
-    // Set up default values, if required.
-    $block_type = $this->blockContentTypeStorage->load($block->bundle());
-    if (!$block->isNew()) {
-      $block->setRevisionLogMessage(NULL);
-    }
-    // Always use the default revision setting.
-    $block->setNewRevision($block_type->shouldCreateNewRevision());
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function form(array $form, FormStateInterface $form_state) {
     $block = $this->entity;
-    $account = $this->currentUser();
+
+    $form = parent::form($form, $form_state);
 
     if ($this->operation == 'edit') {
-      $form['#title'] = $this->t('Edit custom block %label', array('%label' => $block->label()));
+      $form['#title'] = $this->t('Edit custom block %label', ['%label' => $block->label()]);
     }
     // Override the default CSS class name, since the user-defined custom block
     // type name in 'TYPE-block-form' potentially clashes with third-party class
     // names.
     $form['#attributes']['class'][0] = 'block-' . Html::getClass($block->bundle()) . '-form';
 
-    $form['advanced'] = array(
-      '#type' => 'vertical_tabs',
-      '#weight' => 99,
-    );
-
-    // Add a log field if the "Create new revision" option is checked, or if the
-    // current user has the ability to check that option.
-    $form['revision_information'] = array(
-      '#type' => 'details',
-      '#title' => $this->t('Revision information'),
-      // Open by default when "Create new revision" is checked.
-      '#open' => $block->isNewRevision(),
-      '#group' => 'advanced',
-      '#attributes' => array(
-        'class' => array('block-content-form-revision-information'),
-      ),
-      '#attached' => array(
-        'library' => array('block_content/drupal.block_content'),
-      ),
-      '#weight' => 20,
-      '#access' => $block->isNewRevision() || $account->hasPermission('administer blocks'),
-    );
-
-    $form['revision_information']['revision'] = array(
-      '#type' => 'checkbox',
-      '#title' => $this->t('Create new revision'),
-      '#default_value' => $block->isNewRevision(),
-      '#access' => $account->hasPermission('administer blocks'),
-    );
-
-    // Check the revision log checkbox when the log textarea is filled in.
-    // This must not happen if "Create new revision" is enabled by default,
-    // since the state would auto-disable the checkbox otherwise.
-    if (!$block->isNewRevision()) {
-      $form['revision_information']['revision']['#states'] = array(
-        'checked' => array(
-          'textarea[name="revision_log"]' => array('empty' => FALSE),
-        ),
-      );
-    }
-
-    $form['revision_information']['revision_log'] = array(
-      '#type' => 'textarea',
-      '#title' => $this->t('Revision log message'),
-      '#rows' => 4,
-      '#default_value' => $block->getRevisionLog(),
-      '#description' => $this->t('Briefly describe the changes you have made.'),
-    );
-
-    return parent::form($form, $form_state, $block);
+    return $form;
   }
 
   /**
@@ -166,55 +42,21 @@ public function form(array $form, FormStateInterface $form_state) {
    */
   public function save(array $form, FormStateInterface $form_state) {
     $block = $this->entity;
-
-    // Save as a new revision if requested to do so.
-    if (!$form_state->isValueEmpty('revision')) {
-      $block->setNewRevision();
-      // If a new revision is created, save the current user as revision author.
-      $block->setRevisionCreationTime(REQUEST_TIME);
-      $block->setRevisionUserId(\Drupal::currentUser()->id());
-    }
-
     $insert = $block->isNew();
-    $block->save();
-    $context = array('@type' => $block->bundle(), '%info' => $block->label());
-    $logger = $this->logger('block_content');
-    $block_type = $this->blockContentTypeStorage->load($block->bundle());
-    $t_args = array('@type' => $block_type->label(), '%info' => $block->label());
 
-    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));
-    }
+    parent::save($form, $form_state);
 
-    if ($block->id()) {
-      $form_state->setValue('id', $block->id());
-      $form_state->set('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->setRedirectUrl($block->urlInfo('collection'));
+    if ($insert) {
+      if (!$theme = $block->getTheme()) {
+        $theme = $this->config('system.theme')->get('default');
       }
-    }
-    else {
-      // In the unlikely case something went wrong on save, the block will be
-      // rebuilt and block form redisplayed.
-      drupal_set_message($this->t('The block could not be saved.'), 'error');
-      $form_state->setRebuild();
+      $form_state->setRedirect(
+        'block.admin_add',
+        [
+          'plugin_id' => 'block_content:' . $block->uuid(),
+          'theme' => $theme,
+        ]
+      );
     }
   }
 
diff --git a/core/modules/block_content/src/BlockContentTranslationHandler.php b/core/modules/block_content/src/BlockContentTranslationHandler.php
index 781ba1b..9a7c46d 100644
--- a/core/modules/block_content/src/BlockContentTranslationHandler.php
+++ b/core/modules/block_content/src/BlockContentTranslationHandler.php
@@ -15,23 +15,6 @@ class BlockContentTranslationHandler extends ContentTranslationHandler {
   /**
    * {@inheritdoc}
    */
-  public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
-    parent::entityFormAlter($form, $form_state, $entity);
-    // Move the translation fieldset to a vertical tab.
-    if (isset($form['translation'])) {
-      $form['translation'] += array(
-        '#group' => 'additional_settings',
-        '#weight' => 100,
-        '#attributes' => array(
-          'class' => array('block-content-translation-options'),
-        ),
-      );
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   protected function entityFormTitle(EntityInterface $entity) {
     $block_type = BlockContentType::load($entity->bundle());
     return t('<em>Edit @type</em> @title', array('@type' => $block_type->label(), '@title' => $entity->label()));
diff --git a/core/modules/block_content/src/BlockContentTypeInterface.php b/core/modules/block_content/src/BlockContentTypeInterface.php
index 9229dab..da3864e 100644
--- a/core/modules/block_content/src/BlockContentTypeInterface.php
+++ b/core/modules/block_content/src/BlockContentTypeInterface.php
@@ -3,11 +3,12 @@
 namespace Drupal\block_content;
 
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\RevisionableEntityBundleInterface;
 
 /**
  * Provides an interface defining a custom block type entity.
  */
-interface BlockContentTypeInterface extends ConfigEntityInterface {
+interface BlockContentTypeInterface extends ConfigEntityInterface, RevisionableEntityBundleInterface {
 
   /**
    * Returns the description of the block type.
@@ -17,12 +18,4 @@
    */
   public function getDescription();
 
-  /**
-   * Returns whether a new revision should be created by default.
-   *
-   * @return bool
-   *   TRUE if a new revision should be created by default.
-   */
-  public function shouldCreateNewRevision();
-
 }
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 13af342..0f50fbc 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -182,7 +182,14 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['revision_log'] = BaseFieldDefinition::create('string_long')
       ->setLabel(t('Revision log message'))
       ->setDescription(t('The log entry explaining the changes in this revision.'))
-      ->setRevisionable(TRUE);
+      ->setRevisionable(TRUE)
+      ->setDisplayOptions('form', array(
+        'type' => 'string_textarea',
+        'weight' => 25,
+        'settings' => array(
+          'rows' => 4,
+        ),
+      ));
 
     $fields['changed'] = BaseFieldDefinition::create('changed')
       ->setLabel(t('Changed'))
diff --git a/core/modules/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php
index 6fd2254..7995125 100644
--- a/core/modules/content_translation/src/ContentTranslationHandler.php
+++ b/core/modules/content_translation/src/ContentTranslationHandler.php
@@ -384,6 +384,16 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En
         '#multilingual' => TRUE,
       );
 
+      if (isset($form['advanced'])) {
+        $form['content_translation'] += array(
+          '#group' => 'advanced',
+          '#weight' => 100,
+          '#attributes' => array(
+            'class' => array('entity-translation-options'),
+          ),
+        );
+      }
+
       // A new translation is enabled by default.
       $metadata = $this->manager->getTranslationMetadata($entity);
       $status = $new_translation || $metadata->isPublished();
diff --git a/core/modules/field/src/Tests/FormTest.php b/core/modules/field/src/Tests/FormTest.php
index 16625a9..f16886e 100644
--- a/core/modules/field/src/Tests/FormTest.php
+++ b/core/modules/field/src/Tests/FormTest.php
@@ -609,11 +609,11 @@ function testHiddenField() {
     $this->drupalPostForm(NULL, array(), t('Save'));
     preg_match('|' . $entity_type . '/manage/(\d+)|', $this->url, $match);
     $id = $match[1];
-    $this->assertText(t('entity_test_rev @id has been created.', array('@id' => $id)), 'Entity was created');
     $storage = $this->container->get('entity_type.manager')
       ->getStorage($entity_type);
 
     $entity = $storage->load($id);
+    $this->assertRaw(t('@type %label has been created.', ['@type' => 'Test entity - revisions', '%label' => $entity->label()]));
     $this->assertEqual($entity->{$field_name}->value, 99, 'Default value was saved');
 
     // Update the field to remove the default value, and switch to the default
@@ -634,7 +634,7 @@ function testHiddenField() {
     $value = mt_rand(1, 127);
     $edit = array("{$field_name}[0][value]" => $value);
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertText(t('entity_test_rev @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    $this->assertRaw(t('@type %label has been updated.', ['@type' => 'Test entity - revisions', '%label' => $entity->label()]));
     $storage->resetCache([$id]);
     $entity = $storage->load($id);
     $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
diff --git a/core/modules/node/node.js b/core/modules/node/node.js
index 98af6fd..086263d 100644
--- a/core/modules/node/node.js
+++ b/core/modules/node/node.js
@@ -18,21 +18,6 @@
   Drupal.behaviors.nodeDetailsSummaries = {
     attach: function (context) {
       var $context = $(context);
-      $context.find('.node-form-revision-information').drupalSetSummary(function (context) {
-        var $revisionContext = $(context);
-        var revisionCheckbox = $revisionContext.find('.js-form-item-revision input');
-
-          // Return 'New revision' if the 'Create new revision' checkbox is
-          // checked, or if the checkbox doesn't exist, but the revision log does.
-          // For users without the "Administer content" permission the checkbox
-          // won't appear, but the revision log will if the content type is set to
-          // auto-revision.
-        if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $revisionContext.find('.js-form-item-revision-log textarea').length)) {
-          return Drupal.t('New revision');
-        }
-
-        return Drupal.t('No revision');
-      });
 
       $context.find('.node-form-author').drupalSetSummary(function (context) {
         var $authorContext = $(context);
@@ -64,22 +49,6 @@
           return Drupal.t('Not promoted');
         }
       });
-
-      $context.find('fieldset.node-translation-options').drupalSetSummary(function (context) {
-        var $translationContext = $(context);
-        var translate;
-        var $checkbox = $translationContext.find('.js-form-item-translation-translate input');
-
-        if ($checkbox.size()) {
-          translate = $checkbox.is(':checked') ? Drupal.t('Needs to be updated') : Drupal.t('Does not need to be updated');
-        }
-        else {
-          $checkbox = $translationContext.find('.js-form-item-translation-retranslate input');
-          translate = $checkbox.is(':checked') ? Drupal.t('Flag other translations as outdated') : Drupal.t('Do not flag other translations as outdated');
-        }
-
-        return translate;
-      });
     }
   };
 
diff --git a/core/modules/node/node.libraries.yml b/core/modules/node/node.libraries.yml
index 22c93ac..b886594 100644
--- a/core/modules/node/node.libraries.yml
+++ b/core/modules/node/node.libraries.yml
@@ -6,10 +6,8 @@ drupal.node:
   js:
     node.js: {}
   dependencies:
-    - core/jquery
-    - core/drupal
+    - core/drupal.entity
     - core/drupalSettings
-    - core/drupal.form
 
 drupal.node.preview:
   version: VERSION
diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php
index 91d8a90..23f24a4 100644
--- a/core/modules/node/src/Entity/NodeType.php
+++ b/core/modules/node/src/Entity/NodeType.php
@@ -205,4 +205,11 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti
     $storage->resetCache(array_keys($entities));
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function shouldCreateNewRevision() {
+    return $this->isNewRevision();
+  }
+
 }
diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php
index 2828030..f6d47df 100644
--- a/core/modules/node/src/NodeForm.php
+++ b/core/modules/node/src/NodeForm.php
@@ -2,8 +2,9 @@
 
 namespace Drupal\node;
 
-use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\Form\RevisionableContentEntityForm;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\PrivateTempStoreFactory;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -11,7 +12,7 @@
 /**
  * Form handler for the node edit forms.
  */
-class NodeForm extends ContentEntityForm {
+class NodeForm extends RevisionableContentEntityForm {
 
   /**
    * The tempstore factory.
@@ -26,15 +27,15 @@ class NodeForm extends ContentEntityForm {
   protected $hasBeenPreviewed = FALSE;
 
   /**
-   * Constructs a ContentEntityForm object.
+   * Constructs a NodeForm object.
    *
    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
    *   The entity manager.
    * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
    *   The factory for the temp store object.
    */
-  public function __construct(EntityManagerInterface $entity_manager, PrivateTempStoreFactory $temp_store_factory) {
-    parent::__construct($entity_manager);
+  public function __construct(EntityManagerInterface $entity_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, PrivateTempStoreFactory $temp_store_factory) {
+    parent::__construct($entity_manager, $entity_type_bundle_info);
     $this->tempStoreFactory = $temp_store_factory;
   }
 
@@ -44,6 +45,7 @@ public function __construct(EntityManagerInterface $entity_manager, PrivateTempS
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.manager'),
+      $container->get('entity_type.bundle.info'),
       $container->get('user.private_tempstore')
     );
   }
@@ -51,19 +53,6 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  protected function prepareEntity() {
-    /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->entity;
-
-    if (!$node->isNew()) {
-      // Remove the revision log message from the original node entity.
-      $node->revision_log = NULL;
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function form(array $form, FormStateInterface $form_state) {
     // Try to restore from temp store, this must be done before calling
     // parent::form().
@@ -98,10 +87,6 @@ public function form(array $form, FormStateInterface $form_state) {
     /** @var \Drupal\node\NodeInterface $node */
     $node = $this->entity;
 
-    if ($this->operation == 'edit') {
-      $form['#title'] = $this->t('<em>Edit @type</em> @title', array('@type' => node_get_type_label($node), '@title' => $node->label()));
-    }
-
     $current_user = $this->currentUser();
 
     // Changed must be sent to the client, for later overwrite error checking.
@@ -110,47 +95,22 @@ public function form(array $form, FormStateInterface $form_state) {
       '#default_value' => $node->getChangedTime(),
     );
 
-    $form['advanced'] = array(
-      '#type' => 'vertical_tabs',
-      '#attributes' => array('class' => array('entity-meta')),
-      '#weight' => 99,
-    );
     $form = parent::form($form, $form_state);
 
-    // Add a revision_log field if the "Create new revision" option is checked,
-    // or if the current user has the ability to check that option.
-    $form['revision_information'] = array(
-      '#type' => 'details',
-      '#group' => 'advanced',
-      '#title' => t('Revision information'),
-      // Open by default when "Create new revision" is checked.
-      '#open' => $node->isNewRevision(),
-      '#attributes' => array(
-        'class' => array('node-form-revision-information'),
-      ),
-      '#attached' => array(
-        'library' => array('node/drupal.node'),
-      ),
-      '#weight' => 20,
-      '#optional' => TRUE,
-    );
+    $form['advanced']['#attributes']['class'][] = 'entity-meta';
 
-    $form['revision'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Create new revision'),
-      '#default_value' => $node->type->entity->isNewRevision(),
-      '#access' => $current_user->hasPermission('administer nodes') && !$node->isNew(),
-      '#group' => 'revision_information',
-    );
+    $form['revision']['#access'] = $current_user->hasPermission('administer nodes') && !$node->isNew();
 
-    $form['revision_log'] += array(
-      '#states' => array(
-        'visible' => array(
-          ':input[name="revision"]' => array('checked' => TRUE),
-        ),
-      ),
-      '#group' => 'revision_information',
-    );
+    // Clear revision states, because it will conflicts with revision_log state.
+    $form['revision']['#states']['checked'] = [];
+
+    $form['revision_log'] += [
+      '#states' => [
+        'visible' => [
+          ':input[name="revision"]' => ['checked' => TRUE],
+        ],
+      ],
+    ];
 
     // Node author information for administrators.
     $form['author'] = array(
diff --git a/core/modules/node/src/NodeTranslationHandler.php b/core/modules/node/src/NodeTranslationHandler.php
index 9c9741e..2f6d2ab 100644
--- a/core/modules/node/src/NodeTranslationHandler.php
+++ b/core/modules/node/src/NodeTranslationHandler.php
@@ -17,17 +17,7 @@ class NodeTranslationHandler extends ContentTranslationHandler {
   public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
     parent::entityFormAlter($form, $form_state, $entity);
 
-    // Move the translation fieldset to a vertical tab.
     if (isset($form['content_translation'])) {
-      $form['content_translation'] += array(
-        '#group' => 'advanced',
-        '#attributes' => array(
-          'class' => array('node-translation-options'),
-        ),
-      );
-
-      $form['content_translation']['#weight'] = 100;
-
       // We do not need to show these values on node forms: they inherit the
       // basic node property values.
       $form['content_translation']['status']['#access'] = FALSE;
diff --git a/core/modules/node/src/NodeTypeInterface.php b/core/modules/node/src/NodeTypeInterface.php
index c034ffb..1aab64d 100644
--- a/core/modules/node/src/NodeTypeInterface.php
+++ b/core/modules/node/src/NodeTypeInterface.php
@@ -3,11 +3,12 @@
 namespace Drupal\node;
 
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\RevisionableEntityBundleInterface;
 
 /**
  * Provides an interface defining a node type entity.
  */
-interface NodeTypeInterface extends ConfigEntityInterface {
+interface NodeTypeInterface extends ConfigEntityInterface, RevisionableEntityBundleInterface {
 
   /**
    * Determines whether the node type is locked.
@@ -28,7 +29,7 @@ public function isNewRevision();
   /**
    * Sets whether a new revision should be created by default.
    *
-   * @param bool $new_revision_
+   * @param bool $new_revision
    *   TRUE if a new revision should be created by default.
    */
   public function setNewRevision($new_revision);
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 47035ea..4291ce6 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
@@ -15,7 +15,7 @@
  *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
  *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
  *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
+ *       "default" = "\Drupal\entity_test\EntityTestRevisionForm",
  *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
  *     },
  *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
@@ -53,13 +53,6 @@ class EntityTestRev extends EntityTest {
   public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields = parent::baseFieldDefinitions($entity_type);
 
-    $fields['revision_id'] = BaseFieldDefinition::create('integer')
-      ->setLabel(t('Revision ID'))
-      ->setDescription(t('The version id of the test entity.'))
-      ->setReadOnly(TRUE)
-      ->setSetting('unsigned', TRUE);
-
-    $fields['langcode']->setRevisionable(TRUE);
     $fields['name']->setRevisionable(TRUE);
     $fields['user_id']->setRevisionable(TRUE);
 
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestRevisionForm.php b/core/modules/system/tests/modules/entity_test/src/EntityTestRevisionForm.php
new file mode 100644
index 0000000..180f137
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestRevisionForm.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity_test\EntityTestRevisionForm.
+ */
+
+namespace Drupal\entity_test;
+
+use Drupal\Component\Utility\Random;
+use Drupal\Core\Entity\Form\RevisionableContentEntityForm;
+use Drupal\Core\Form\FormStateInterface;
+
+class EntityTestRevisionForm extends RevisionableContentEntityForm {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function prepareEntity() {
+    if (empty($this->entity->name->value)) {
+      // Assign a random name to new EntityTest entities, to avoid repetition in
+      // tests.
+      $random = new Random();
+      $this->entity->name->value = $random->name();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(array $form, FormStateInterface $form_state) {
+    try {
+      parent::save($form, $form_state);
+    }
+    catch (\Exception $e) {
+      \Drupal::state()->set('entity_test.form.save.exception', get_class($e) . ': ' . $e->getMessage());
+    }
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
index 23cf034..e49ee7e 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
@@ -102,6 +102,9 @@ public function testEntityTypeUpdateWithoutData() {
     $expected = array(
       'entity_test_update' => array(
         t('The %entity_type entity type needs to be updated.', ['%entity_type' => $this->entityManager->getDefinition('entity_test_update')->getLabel()]),
+        // The revision key is now defined, so the revision field needs to be
+        // created.
+        t('The %field_name field needs to be installed.', ['%field_name' => 'Revision ID']),
       ),
     );
     $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected); //, 'EntityDefinitionUpdateManager reports the expected change summary.');
@@ -797,7 +800,7 @@ public function testBaseFieldEntityKeyUpdateWithExistingData() {
   /**
    * Check that field schema is correctly handled with long-named fields.
    */
-  function testLongNameFieldIndexes() {
+  public function testLongNameFieldIndexes() {
     $this->addLongNameBaseField();
     $entity_type_id = 'entity_test_update';
     $entity_type = $this->entityManager->getDefinition($entity_type_id);
