diff --git a/src/Form/RevisionRevertForm.php b/src/Form/RevisionRevertForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..de2e049a50aec18a043f84690f1bba2b55a799da
--- /dev/null
+++ b/src/Form/RevisionRevertForm.php
@@ -0,0 +1,173 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\Form\RevisionRevertForm.
+ */
+
+namespace Drupal\entity\Form;
+
+use Drupal\Core\Datetime\DateFormatterInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\RevisionableInterface;
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\entity\Revision\EntityRevisionLogInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+class RevisionRevertForm extends ConfirmFormBase {
+
+  /**
+   * The entity revision.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface|\Drupal\Core\Entity\RevisionableInterface|\Drupal\entity\Revision\EntityRevisionLogInterface
+   */
+  protected $revision;
+
+  /**
+   * The date formatter.
+   *
+   * @var \Drupal\Core\Datetime\DateFormatterInterface
+   */
+  protected $dateFormatter;
+
+  /**
+   * The entity bundle information.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $bundleInformation;
+
+  /**
+   * Creates a new RevisionRevertForm instance.
+   *
+   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
+   *   The date formatter.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_information
+   *   The bundle information.
+   */
+  public function __construct(DateFormatterInterface $date_formatter, EntityTypeBundleInfoInterface $bundle_information) {
+    $this->dateFormatter = $date_formatter;
+    $this->bundleInformation = $bundle_information;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('date.formatter'),
+      $container->get('entity_type.bundle.info')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'entity_revision_revert_confirm';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    if ($this->revision instanceof EntityRevisionLogInterface) {
+      return $this->t('Are you sure you want to revert to the revision from %revision-date?', ['%revision-date' => $this->dateFormatter->format($this->revision->getRevisionLogMessage())]);
+    }
+    return $this->t('Are you sure you want to revert the revision?');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    if ($this->revision->getEntityType()->hasLinkTemplate('version-history')) {
+      return $this->revision->toUrl('version-history');
+    }
+    return $this->revision->toUrl();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return t('Revert');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return '';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, $_entity_revision = NULL, Request $request = NULL) {
+    $this->revision = $_entity_revision;
+    $form = parent::buildForm($form, $form_state);
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    // The revision timestamp will be updated when the revision is saved. Keep
+    // the original one for the confirmation message.
+
+    $this->revision = $this->prepareRevision($this->revision);
+    if ($this->revision instanceof EntityRevisionLogInterface) {
+      $original_revision_timestamp = $this->revision->getRevisionCreationTime();
+
+      $this->revision->setRevisionLogMessage($this->t('Copy of the revision from %date.', ['%date' => $this->dateFormatter->format($original_revision_timestamp)]));
+      drupal_set_message(t('@type %title has been reverted to the revision from %revision-date.', ['@type' => $this->getBundleLabel($this->revision), '%title' => $this->revision->label(), '%revision-date' => $this->dateFormatter->format($original_revision_timestamp)]));
+    }
+    else {
+      drupal_set_message(t('@type %title has been reverted', ['@type' => $this->getBundleLabel($this->revision), '%title' => $this->revision->label()]));
+    }
+
+    $this->revision->save();
+
+    $this->logger('content')->notice('@type: reverted %title revision %revision.', ['@type' => $this->revision->bundle(), '%title' => $this->revision->label(), '%revision' => $this->revision->getRevisionId()]);
+    $form_state->setRedirect(
+      "entity.{$this->revision->getEntityTypeId()}.version_history",
+      [$this->revision->getEntityTypeId() => $this->revision->id()]
+    );
+  }
+
+  /**
+   * Prepares a revision to be reverted.
+   *
+   * @param \Drupal\Core\Entity\RevisionableInterface $revision
+   *   The revision to be reverted.
+   *
+   * @return \Drupal\Core\Entity\RevisionableInterface
+   *   The prepared revision ready to be stored.
+   */
+  protected function prepareRevision(RevisionableInterface $revision) {
+    $revision->setNewRevision();
+    $revision->isDefaultRevision(TRUE);
+
+    return $revision;
+  }
+
+  /**
+   * Returns a bundle label.
+   *
+   * @param \Drupal\Core\Entity\RevisionableInterface $revision
+   *   The entity revision.
+   *
+   * @return string
+   */
+  protected function getBundleLabel(RevisionableInterface $revision) {
+    /** @var \Drupal\Core\Entity\EntityInterface|\Drupal\Core\Entity\RevisionableInterface $revision */
+    $bundle_info = $this->bundleInformation->getBundleInfo($revision->getEntityTypeId());
+    return $bundle_info[$revision->bundle()]['label'];
+  }
+
+}
diff --git a/src/Revision/RevisionableContentEntityBase.php b/src/Revision/RevisionableContentEntityBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b6ae620e3bea787a511879385da47451e1f4e99
--- /dev/null
+++ b/src/Revision/RevisionableContentEntityBase.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\entity\Revision\RevisionableContentEntityBase.
+ */
+
+namespace Drupal\entity\Revision;
+
+use Drupal\Core\Entity\ContentEntityBase;
+
+/**
+ * Provides an entity class with revisions.
+ */
+abstract class RevisionableContentEntityBase extends ContentEntityBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function urlRouteParameters($rel) {
+    $uri_route_parameters = [];
+
+    if ($rel != 'collection') {
+      // The entity ID is needed as a route parameter.
+      $uri_route_parameters[$this->getEntityTypeId()] = $this->id();
+    }
+    if (strpos($this->getEntityType()->getLinkTemplate($rel), $this->getEntityTypeId() . '_revision') !== FALSE) {
+      $uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
+    }
+
+    return $uri_route_parameters;
+  }
+
+}
diff --git a/src/Routing/RevisionRouteProvider.php b/src/Routing/RevisionRouteProvider.php
index f9e6576542eb80bf2b6df6028acf64f239e8a77e..d539c6150b6083964ad09fcb87f688ff1f2b223b 100644
--- a/src/Routing/RevisionRouteProvider.php
+++ b/src/Routing/RevisionRouteProvider.php
@@ -26,6 +26,9 @@ class RevisionRouteProvider implements EntityRouteProviderInterface {
     if ($view_route = $this->getRevisionViewRoute($entity_type)) {
       $collection->add("entity.$entity_type_id.revision", $view_route);
     }
+    if ($view_route = $this->getRevisionRevertRoute($entity_type)) {
+      $collection->add("entity.$entity_type_id.revision_revert_form", $view_route);
+    }
 
     return $collection;
   }
@@ -62,4 +65,36 @@ class RevisionRouteProvider implements EntityRouteProviderInterface {
     }
   }
 
+  /**
+   * Gets the entity revision revert route.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return \Symfony\Component\Routing\Route|null
+   *   The generated route, if available.
+   */
+  protected function getRevisionRevertRoute(EntityTypeInterface $entity_type) {
+    if ($entity_type->hasLinkTemplate('revision-revert-form')) {
+      $entity_type_id = $entity_type->id();
+      $route = new Route($entity_type->getLinkTemplate('revision-revert-form'));
+      $route->addDefaults([
+        '_form' => '\Drupal\entity\Form\RevisionRevertForm',
+        'title' => 'Revert to earlier revision',
+      ]);
+      $route->addRequirements([
+        '_entity_access_revision' => "$entity_type_id.update",
+      ]);
+      $route->setOption('parameters', [
+        $entity_type->id() => [
+          'type' => 'entity:' . $entity_type->id(),
+        ],
+        $entity_type->id() . '_revision' => [
+          'type' => 'entity_revision:' . $entity_type->id(),
+        ],
+      ]);
+      return $route;
+    }
+  }
+
 }
diff --git a/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php b/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php
index 267e2cef2bdc1148b754b60a96b9f5765e07e623..d49e0bdcedfc0ca2842ad47eceb773446b0811c6 100644
--- a/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php
+++ b/tests/modules/entity_module_test/src/Entity/EnhancedEntity.php
@@ -7,11 +7,11 @@
 
 namespace Drupal\entity_module_test\Entity;
 
-use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\entity\EntityKeysFieldsTrait;
 use Drupal\entity\Revision\EntityRevisionLogTrait;
+use Drupal\entity\Revision\RevisionableContentEntityBase;
 
 /**
  * Provides a test entity which uses all the capabilities of entity module.
@@ -27,6 +27,7 @@ use Drupal\entity\Revision\EntityRevisionLogTrait;
  *       "delete" = "\Drupal\Core\Entity\EntityDeleteForm",
  *     },
  *     "route_provider" = {
+ *       "html" = "\Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
  *       "revision" = "\Drupal\entity\Routing\RevisionRouteProvider",
  *       "create" = "\Drupal\entity\Routing\CreateHtmlRouteProvider",
  *     },
@@ -47,12 +48,14 @@ use Drupal\entity\Revision\EntityRevisionLogTrait;
  *   links = {
  *     "add-page" = "/entity_test_enhanced/add",
  *     "add-form" = "/entity_test_enhanced/add/{type}",
+ *     "canonical" = "/entity_test_enhanced/{entity_test_enhanced}",
  *     "revision" = "/entity_test_enhanced/{entity_test_enhanced}/revisions/{entity_test_enhanced_revision}/view",
+ *     "revision-revert-form" = "/entity_test_enhanced/{entity_test_enhanced}/revisions/{entity_test_enhanced_revision}/revert",
  *   },
  *   bundle_entity_type = "entity_test_enhanced_bundle"
  * )
  */
-class EnhancedEntity extends ContentEntityBase {
+class EnhancedEntity extends RevisionableContentEntityBase {
 
   use EntityRevisionLogTrait;
   use EntityKeysFieldsTrait;
diff --git a/tests/src/Kernel/RevisionBasicUITest.php b/tests/src/Kernel/RevisionBasicUITest.php
index b716c66b51182e95fec0e62e9407f423f7dc2ae3..efb6f75ddb43ed663b3bd3f5adf5478354962ce6 100644
--- a/tests/src/Kernel/RevisionBasicUITest.php
+++ b/tests/src/Kernel/RevisionBasicUITest.php
@@ -80,4 +80,33 @@ class RevisionBasicUITest extends KernelTestBase {
     $this->assertContains('rev 2', $response->getContent());
   }
 
+  public function testRevisionRevert() {
+    $entity = EnhancedEntity::create([
+      'name' => 'rev 1',
+      'type' => 'entity_test_enhance',
+    ]);
+    $entity->save();
+    $entity->name->value = 'rev 2';
+    $entity->setNewRevision(TRUE);
+    $entity->isDefaultRevision(TRUE);
+    $entity->save();
+
+    $role = Role::create(['id' => 'test_role']);
+    $role->grantPermission('administer entity_test_enhanced');
+    $role->grantPermission('revert all entity_test_enhanced revisions');
+    $role->save();
+
+    $user = User::create([
+      'name' => 'Test user',
+    ]);
+    $user->addRole($role->id());
+    \Drupal::service('account_switcher')->switchTo($user);
+
+    /** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
+    $http_kernel = \Drupal::service('http_kernel');
+    $request = Request::create($entity->url('revision-revert-form'));
+    $response = $http_kernel->handle($request);
+    $this->assertEquals(200, $response->getStatusCode());
+  }
+
 }