diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f3b65a2..cfeb863 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -5,20 +5,22 @@
  * Configuration system that lets administrators modify the workings of the site.
  */
 
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Database\DatabaseExceptionWrapper;
+use Drupal\Core\Entity\Query\QueryException;
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ExtensionDiscovery;
-use Drupal\Core\Form\FormState;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\StringTranslation\TranslationWrapper;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Menu\MenuTreeParameters;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\StringTranslation\TranslationWrapper;
 use Drupal\Core\Url;
-use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\user\UserInterface;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 use GuzzleHttp\Exception\RequestException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * New users will be set to the default time zone at registration.
@@ -1032,11 +1034,65 @@ function system_sort_themes($a, $b) {
  * Implements hook_system_info_alter().
  */
 function system_system_info_alter(&$info, Extension $file, $type) {
-  // Remove page-top and page-bottom from the blocks UI since they are reserved for
-  // modules to populate from outside the blocks system.
-  if ($type == 'theme') {
-    $info['regions_hidden'][] = 'page_top';
-    $info['regions_hidden'][] = 'page_bottom';
+  switch ($type) {
+    case 'theme':
+      // Remove page-top and page-bottom from the blocks UI since they are
+      // reserved for modules to populate from outside the blocks system.
+      $info['regions_hidden'][] = 'page_top';
+      $info['regions_hidden'][] = 'page_bottom';
+      break;
+
+    case 'module':
+      // @todo Unify this with field_system_info_alter() once purging is
+      //   supported for any field. See https://www.drupal.org/node/2282119.
+      $module_name = $file->getName();
+      if ($module_name != 'field') {
+        $entity_manager = \Drupal::entityManager();
+        foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) {
+          try {
+            // We skip entity-defining modules, otherwise deleting all entities
+            // would be required before being able to uninstall them.
+            if ($entity_type->getProvider() != $module_name && $entity_type->isFieldable()) {
+              try {
+                $has_data = \Drupal::entityQuery($entity_type_id)->count()->execute();
+              }
+              catch (QueryException $e) {
+                // If an entity type can't be queried, treat it has having no
+                // data for purposes of allowing its fields' field type modules
+                // to be uninstalled.
+                // @todo Require all storage handlers to support querying:
+                //   https://www.drupal.org/node/2337753.
+                $has_data = FALSE;
+              }
+              catch (DatabaseExceptionWrapper $e) {
+                // During KernelTestBase tests, some entity schema are not
+                // installed.
+                if (!\Drupal::database()->schema()->tableExists($entity_type->getBaseTable())) {
+                  $has_data = FALSE;
+                }
+                else {
+                  throw $e;
+                }
+              }
+              if ($has_data) {
+                foreach ($entity_manager->getFieldStorageDefinitions($entity_type_id) as $storage_definition) {
+                  if ($storage_definition->getProvider() == $module_name) {
+                    $info['required'] = TRUE;
+                    $info['explanation'] = t('Fields type(s) in use');
+                    break;
+                  }
+                }
+              }
+            }
+          }
+          catch (PluginNotFoundException $e) {
+            // This may happen if the current module is being installed. In this
+            // case we can safely ignore it, as we are interested in blocking
+            // module uninstallation.
+          }
+        }
+      }
+      break;
   }
 }
 
