diff --git a/core/lib/Drupal/Component/Version/CoreSemver.php b/core/lib/Drupal/Component/Version/CoreSemver.php
new file mode 100644
index 0000000000..9f094ece7e
--- /dev/null
+++ b/core/lib/Drupal/Component/Version/CoreSemver.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\Component\Version;
+
+use Composer\Semver\Semver;
+
+/**
+ *
+ */
+class CoreSemver {
+
+  /**
+   * Determine if given version satisfies given constraints.
+   *
+   * @param string $version
+   * @param string $constraints
+   *
+   * @return bool
+   */
+  public static function satisfies($version, $constraints) {
+    if ('8.x' === $constraints) {
+     $constraints = '^8';
+    }
+    return Semver::satisfies($version, $constraints);
+  }
+
+}
diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php
index 106f4e2915..76396407d4 100644
--- a/core/modules/system/src/Controller/SystemController.php
+++ b/core/modules/system/src/Controller/SystemController.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Url;
 use Drupal\system\SystemManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Component\Version\CoreSemver;
 
 /**
  * Returns responses for System routes.
@@ -223,7 +224,7 @@ public function themesPage() {
 
       if (empty($theme->status)) {
         // Ensure this theme is compatible with this version of core.
-        $theme->incompatible_core = !isset($theme->info['core']) || ($theme->info['core'] != \DRUPAL::CORE_COMPATIBILITY);
+        $theme->incompatible_core = !isset($theme->info['core']) || !CoreSemver::satisfies(\Drupal::VERSION, $theme->info['core']);
         // Require the 'content' region to make sure the main page
         // content has a common place in all themes.
         $theme->incompatible_region = !isset($theme->info['regions']['content']);
diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php
index cabbe2ebaa..bfc90a592c 100644
--- a/core/modules/system/src/Form/ModulesListForm.php
+++ b/core/modules/system/src/Form/ModulesListForm.php
@@ -3,6 +3,8 @@
 namespace Drupal\system\Form;
 
 use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Version\Constraint;
+use Drupal\Component\Version\CoreSemver;
 use Drupal\Core\Config\PreExistingConfigException;
 use Drupal\Core\Config\UnmetDependenciesException;
 use Drupal\Core\Access\AccessManagerInterface;
@@ -20,6 +22,7 @@
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
+
 /**
  * Provides module installation interface.
  *
@@ -295,10 +298,15 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
     $reasons = [];
 
     // Check the core compatibility.
-    if ($module->info['core'] != \Drupal::CORE_COMPATIBILITY) {
+    if (!CoreSemver::satisfies(\Drupal::VERSION, $module->info['core'])) {
       $compatible = FALSE;
       $reasons[] = $this->t('This version is not compatible with Drupal @core_version and should be replaced.', [
-        '@core_version' => \Drupal::CORE_COMPATIBILITY,
+        '@core_version' => \Drupal::VERSION,
+      ]);
+      $row['#requires']['core'] = $this->t('Drupal Core (@core_requirement) (<span class="admin-missing">incompatible with</span> version @core_version)', [
+        '@module' => $module->getName(),
+        '@core_requirement' => $module->info['core'],
+        '@core_version' => \Drupal::VERSION,
       ]);
     }
 
@@ -342,7 +350,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) {
         }
         // Disable the checkbox if the dependency is incompatible with this
         // version of Drupal core.
-        elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) {
+        elseif (!CoreSemver::satisfies(\Drupal::VERSION, $modules[$dependency]->info['core'])) {
           $row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', [
             '@module' => $name,
           ]);
diff --git a/core/modules/system/tests/modules/system_incompatible_core_version_test_9x/system_incompatible_core_version_test_9x.info.yml b/core/modules/system/tests/modules/system_incompatible_core_version_test_9x/system_incompatible_core_version_test_9x.info.yml
new file mode 100644
index 0000000000..4bc6e455a0
--- /dev/null
+++ b/core/modules/system/tests/modules/system_incompatible_core_version_test_9x/system_incompatible_core_version_test_9x.info.yml
@@ -0,0 +1,6 @@
+name: 'System incompatible core 9.x version test'
+type: module
+description: 'Support module for testing system dependencies.'
+package: Testing
+version: 9.0.0
+core: 9.x
diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module
index affc20ea42..bf96719f33 100644
--- a/core/modules/system/tests/modules/system_test/system_test.module
+++ b/core/modules/system/tests/modules/system_test/system_test.module
@@ -62,6 +62,10 @@ function system_test_system_info_alter(&$info, Extension $file, $type) {
     }
   }
 
+  if (($core_requirement = \Drupal::state()->get('dependency_test.core_version_requirement')) && $file->getName() === 'common_test') {
+    $info['core'] = $core_requirement;
+  }
+
   // Make the system_dependencies_test visible by default.
   if ($file->getName() == 'system_dependencies_test') {
     $info['hidden'] = FALSE;
@@ -71,6 +75,8 @@ function system_test_system_info_alter(&$info, Extension $file, $type) {
     'system_incompatible_core_version_dependencies_test',
     'system_incompatible_module_version_test',
     'system_incompatible_core_version_test',
+    'system_incompatible_core_version_test_9x',
+    'system_compatible_core_version_test_80x',
   ])) {
     $info['hidden'] = FALSE;
   }
diff --git a/core/modules/system/tests/src/Functional/Module/DependencyTest.php b/core/modules/system/tests/src/Functional/Module/DependencyTest.php
index 2e0e60923c..22f1c74382 100644
--- a/core/modules/system/tests/src/Functional/Module/DependencyTest.php
+++ b/core/modules/system/tests/src/Functional/Module/DependencyTest.php
@@ -102,6 +102,29 @@ public function testIncompatiblePhpVersionDependency() {
     $this->assert(count($checkbox) == 1, 'Checkbox for the module is disabled.');
   }
 
+  /**
+   * Tests enabling modules with different core version specifications.
+   */
+  public function testCoreVersionDependency() {
+    $assert_session = $this->assertSession();
+    $page = $this->getSession()->getPage();
+    list($major, $minor) = explode('.', \Drupal::VERSION);
+    $next_minor = "$major." . ((int) $minor + 1) . ".x";
+    \Drupal::state()->set('dependency_test.core_version_requirement', $next_minor);
+    $this->drupalGet('admin/modules');
+    $assert_session->fieldDisabled('modules[system_incompatible_core_version_test_9x][enable]');
+    $assert_session->fieldDisabled('modules[common_test][enable]');
+
+    $current_minor = "$major.$minor.x";
+    \Drupal::state()->set('dependency_test.core_version_requirement', $current_minor);
+    $this->drupalGet('admin/modules');
+    $checkbox = $page->find('css', '[name="modules[common_test][enable]"]');
+    $this->assertFalse($checkbox->hasAttribute('disabled'));
+    $edit['modules[common_test][enable]'] = 'common_test';
+    $this->drupalPostForm('admin/modules', $edit, t('Install'));
+    $this->assertModules(['common_test'], TRUE);
+  }
+
   /**
    * Tests enabling a module that depends on a module which fails hook_requirements().
    */
diff --git a/core/tests/Drupal/Tests/Component/Version/CoreSemverTest.php b/core/tests/Drupal/Tests/Component/Version/CoreSemverTest.php
new file mode 100644
index 0000000000..0b7f255e38
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Version/CoreSemverTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Drupal\Tests\Component\Version;
+
+use Composer\Semver\Semver;
+use Composer\Semver\VersionParser;
+use Drupal\Component\Version\CoreSemver;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\Version\CoreSemver
+ * @group Version
+ */
+class CoreSemverTest extends TestCase {
+
+  /**
+   * @covers ::satisfies
+   * @dataProvider providerSatisfies
+   */
+  public function testSatisfies($version, $constraints, $result) {
+    $this->assertSame($result, CoreSemver::satisfies($version, $constraints));
+    // Proving we actually don't need CoreSemver.
+    $this->assertSame($result, Semver::satisfies($version, $constraints));
+  }
+
+  public function providerSatisfies() {
+    $cases = [
+      ['8.8.0-dev', '8.x', TRUE],
+      ['8.8.0', '8.x', TRUE],
+      ['8.9.9', '8.x', TRUE],
+      ['8.0.0', '8.x', TRUE],
+      ['9.0.0', '8.x', FALSE],
+      ['9.1.0', '8.x', FALSE],
+      ['8.8.0', '~8', TRUE],
+      ['8.8.0', '^8', TRUE],
+      ['8.7.0', '^8.7.6', FALSE],
+      ['8.7.6', '^8.7.6', TRUE],
+      ['8.7.8', '^8.7.6', TRUE],
+      ['9.0.0', '^8.7.6', FALSE],
+      ['8.0.0', '8 - 9', TRUE],
+      ['9.1.1', '8 - 9', TRUE],
+      ['9.1.1', '8.7.6 - 9', TRUE],
+      ['8.7.8', '8.7.6 - 9', TRUE],
+      ['8.6.8', '8.7.6 - 9', FALSE],
+      ['8.6.8', '^9', FALSE],
+      ['9.1.1', '^9', TRUE],
+      ['9.0.0', '9.x', TRUE],
+      ['8.8.0', '9.x', FALSE],
+      ['8.8.0', '7.x', FALSE],
+    ];
+    $tests = [];
+    foreach ($cases as $case) {
+      $tests[$case[0] . ":" . $case[1]] = $case;
+    }
+    return $tests;
+  }
+
+
+  /**
+   * Test to just prove that 8.x actually equals ^8 what we want in composer!
+   */
+  public function testSemver() {
+    $versionParser = new VersionParser();
+
+    $this->assertEquals((string) $versionParser->parseConstraints('8.x'),(string) $versionParser->parseConstraints('^8'));
+    $this->assertEquals((string) "[>= 8.0.0.0-dev < 9.0.0.0-dev]",(string) $versionParser->parseConstraints('8.x'));
+    $this->assertNotEquals((string) $versionParser->parseConstraints('8.x'),(string) $versionParser->parseConstraints('>8'));
+  }
+
+}
