diff --git a/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php b/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php
index 7cd33ab..9cd3f7a 100644
--- a/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php
+++ b/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Core\Url;
 
 /**
  * Validates module uninstall readiness based on existing content entities.
@@ -37,10 +38,14 @@ public function __construct(EntityManagerInterface $entity_manager, TranslationI
    */
   public function validate($module) {
     $entity_types = $this->entityManager->getDefinitions();
-    $reasons = array();
+    $reasons = [];
     foreach ($entity_types as $entity_type) {
       if ($module == $entity_type->getProvider() && $entity_type instanceof ContentEntityTypeInterface && $this->entityManager->getStorage($entity_type->id())->hasData()) {
-        $reasons[] = $this->t('There is content for the entity type: @entity_type', array('@entity_type' => $entity_type->getLabel()));
+        $reasons[] = $this->t('There is content for the entity type: @entity_type. <a href=":link">Remove @entity_type_plural</a>.', [
+          '@entity_type' => $entity_type->getLabel(),
+          '@entity_type_plural' => $entity_type->getPluralLabel(),
+          ':link' => Url::fromRoute('system.prepare_modules_entity_uninstall', ['entity_type_id' => $entity_type->id()])->toString(),
+        ]);
       }
     }
     return $reasons;
diff --git a/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
new file mode 100644
index 0000000..8ee95ee
--- /dev/null
+++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
@@ -0,0 +1,169 @@
+<?php
+
+namespace Drupal\system\Form;
+
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
+/**
+ * Provides a form removing module content entities data before uninstallation.
+ */
+class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
+
+  /**
+   * The entity type ID of the entities to delete.
+   *
+   * @var string
+   */
+  protected $entityTypeId;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'system_prepare_modules_entity_uninstall';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    $entity_type = \Drupal::entityTypeManager()->getDefinition($this->entityTypeId);
+
+    return $this->t('Are you sure you want to delete all @entity_type_plural?', ['@entity_type_plural' => $entity_type->getPluralLabel()]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    $entity_type = \Drupal::entityTypeManager()->getDefinition($this->entityTypeId);
+    // Display how many content entities there are to remove.
+    $count = \Drupal::entityQuery($this->entityTypeId)->count()->execute();
+
+    return $this->formatPlural($count, 'There is 1 @entity_type entity to remove. This action cannot be undone.', 'There are @count @entity_type_plural to remove. This action cannot be undone.', ['@entity_type' => $entity_type->getSingularLabel(), '@entity_type_plural' => $entity_type->getPluralLabel()]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    $entity_type = \Drupal::entityTypeManager()->getDefinition($this->entityTypeId);
+
+    return $this->t('Delete all @entity_type_plural', ['@entity_type_plural' => $entity_type->getPluralLabel()]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    return Url::fromRoute('system.modules_uninstall');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL) {
+    $this->entityTypeId = $entity_type_id;
+
+    $form['entity_type_id'] = [
+      '#type' => 'value',
+      '#value' => $entity_type_id,
+    ];
+
+    $form['advanced_options'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Advanced options'),
+      '#weight' => 10,
+      '#tree' => FALSE,
+    ];
+    $count = \Drupal::entityQuery($this->entityTypeId)->count()->execute();
+    $form['advanced_options']['limit'] = [
+      '#type' => 'number',
+      '#title' => $this->t('Limit'),
+      '#description' => $this->t('Select how many items should be deleted at once in a single batch run.'),
+      '#default_value' => ($count < 100) ? $count : 100,
+    ];
+
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $entity_type_id = $form_state->getValue('entity_type_id');
+    $limit = $form_state->getValue('limit');
+
+    $entity_type_plural = \Drupal::entityTypeManager()->getDefinition($entity_type_id)->getPluralLabel();
+    $batch = [
+      'title' => t('Deleting @entity_type_plural', [
+        '@entity_type_plural' => $entity_type_plural,
+      ]),
+      'operations' => [
+        [
+          [__CLASS__, 'deleteContentEntities'], [$entity_type_id, $limit],
+        ],
+      ],
+      'finished' => [__CLASS__, 'moduleBatchFinished'],
+      'progress_message' => '',
+    ];
+    batch_set($batch);
+  }
+
+  /**
+   * Deletes the content entities of the specified entity type.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID from which data will be deleted.
+   * @param int $limit
+   *   How many items to remove in a batch run.
+   * @param array|\ArrayAccess $context
+   *   The batch context array, passed by reference.
+   */
+  public static function deleteContentEntities($entity_type_id, $limit, &$context) {
+    $storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);
+
+    // Set the entity type ID in the results array so we can acess it in the
+    // batch finished callback.
+    $context['results']['entity_type_id'] = $entity_type_id;
+
+    if (!isset($context['sandbox']['progress'])) {
+      $context['sandbox']['progress'] = 0;
+      $context['sandbox']['max'] = \Drupal::entityQuery($entity_type_id)->count()->execute();
+    }
+
+    $entity_ids = $storage->getQuery()->range(0, $limit)->execute();
+    if ($entity_types = $storage->loadMultiple($entity_ids)) {
+      $storage->delete($entity_types);
+    }
+    $context['sandbox']['progress'] += count($entity_ids);
+
+    // Inform the batch engine that we are not finished,
+    // and provide an estimation of the completion level we reached.
+    if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+      $context['message'] = t('Deleting items... Completed @percentage% (@current of @total).', ['@percentage' => round(100 * $context['sandbox']['progress'] / $context['sandbox']['max']), '@current' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']]);
+
+    }
+    else {
+      $context['finished'] = 1;
+    }
+  }
+
+  /**
+   * Implements callback_batch_finished().
+   *
+   * Finishes the module batch, redirect to the uninstall page and output the
+   * successful data deletion message.
+   */
+  public static function moduleBatchFinished($success, $results, $operations) {
+    $entity_type_plural = \Drupal::entityTypeManager()->getDefinition($results['entity_type_id'])->getPluralLabel();
+    drupal_set_message(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
+
+    return new RedirectResponse(Url::fromRoute('system.modules_uninstall')->setAbsolute()->toString());
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Module/PrepareUninstallTest.php b/core/modules/system/src/Tests/Module/PrepareUninstallTest.php
new file mode 100644
index 0000000..da1e7e3
--- /dev/null
+++ b/core/modules/system/src/Tests/Module/PrepareUninstallTest.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\system\Tests\Module;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests that modules can be uninstalled.
+ *
+ * Here we take the Node module as example to test the prepare uninstallation.
+ *
+ * @group Module
+ */
+class PrepareUninstallTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['node'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $admin_user = $this->drupalCreateUser(['administer modules']);
+    $this->drupalLogin($admin_user);
+
+    // Create some nodes.
+    $this->drupalCreateNode(['type' => 'page']);
+    $this->drupalCreateNode(['type' => 'page']);
+    $this->drupalCreateNode(['type' => 'article']);
+    $this->drupalCreateNode(['type' => 'article']);
+  }
+
+  /**
+   * Tests that Node module can be uninstalled.
+   */
+  public function testUninstall() {
+    // Check Node cannot be uninstalled yet, there is content to be removed.
+    $this->drupalGet('admin/modules/uninstall');
+    $this->assertText(t('Remove content items'));
+    $this->assertLinkByHref('admin/modules/uninstall/entity/node');
+
+    // Delete Node data.
+    $this->drupalGet('admin/modules/uninstall/entity/node');
+    $this->assertText(t('There are 4 content items to remove. This action cannot be undone.'));
+    $this->drupalPostForm(NULL, ['limit' => 1], t('Delete all content items'));
+
+    // Check we are redirected to the uninstall page and data has been removed.
+    $this->assertUrl('admin/modules/uninstall', []);
+    $this->assertText(t('All content items have been deleted.'));
+
+    // Check there is no more data to be deleted, Node is ready to be disabled.
+    $this->assertText(t('Allows content to be submitted to the site and displayed on pages.'));
+    $this->assertNoLinkByHref('admin/modules/uninstall/entity/node');
+
+    // Uninstall Node module.
+    $this->drupalPostForm('admin/modules/uninstall', ['uninstall[node]' => TRUE], t('Uninstall'));
+    $this->drupalPostForm(NULL, [], t('Uninstall'));
+    $this->assertText(t('The selected modules have been uninstalled.'));
+    $this->assertNoText(t('Allows content to be submitted to the site and displayed on pages.'));
+  }
+
+}
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 547b083..6927d6b 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -423,6 +423,14 @@ system.modules_uninstall_confirm:
   requirements:
     _permission: 'administer modules'
 
+system.prepare_modules_entity_uninstall:
+  path: '/admin/modules/uninstall/entity/{entity_type_id}'
+  defaults:
+    _form: '\Drupal\system\Form\PrepareModulesEntityUninstallForm'
+    _title_callback: '\Drupal\system\Form\PrepareModulesEntityUninstallForm::formTitle'
+  requirements:
+    _permission: 'administer modules'
+
 system.timezone:
   path: '/system/timezone/{abbreviation}/{offset}/{is_daylight_saving_time}'
   defaults:
diff --git a/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php b/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
index 9beac7a..ff400e1 100644
--- a/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
+++ b/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
@@ -3,7 +3,6 @@
 namespace Drupal\Tests\system\Kernel\Extension;
 
 use Drupal\Core\Extension\MissingDependencyException;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
 use \Drupal\Core\Extension\ModuleUninstallValidatorException;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\KernelTests\KernelTestBase;
@@ -37,16 +36,6 @@ protected function setUp() {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function register(ContainerBuilder $container) {
-    parent::register($container);
-    // Put a fake route bumper on the container to be called during uninstall.
-    $container
-      ->register('router.dumper', 'Drupal\Core\Routing\NullMatcherDumper');
-  }
-
-  /**
    * The basic functionality of retrieving enabled modules.
    */
   function testModuleList() {
