diff -u b/src/ProjectInfoTrait.php b/src/ProjectInfoTrait.php
--- b/src/ProjectInfoTrait.php
+++ b/src/ProjectInfoTrait.php
@@ -10,20 +10,62 @@
 trait ProjectInfoTrait {
 
   /**
+   * Get extension list.
+   *
+   * @param string $extension_type
+   *
+   * @return \Drupal\Core\Extension\ExtensionList
+   */
+  protected function getExtensionList($extension_type) {
+    if (isset($this->{$extension_type})) {
+      $list = $this->{$extension_type};
+    }
+    else {
+      $list = \Drupal::service("extension.list.$extension_type");
+    }
+    return $list;
+  }
+
+  /**
+   * Returns an array of info files information of available extensions.
+   *
+   * @param string $extension_type
+   *   The extension type.
+   *
+   * @return array
+   *   An associative array of extension information arrays, keyed by extension
+   *   name.
+   */
+  protected function getInfos($extension_type) {
+    $file_paths = $this->getExtensionList($extension_type)->getPathnames();
+    $infos = $this->getExtensionList($extension_type)->getAllAvailableInfo();
+    return array_map(function ($key, array $info) use ($file_paths) {
+      $info['packaged'] = $info['project'] ?? FALSE;
+      $info['project'] = $this->getProjectName($key, $info);
+      $info['install path'] = $file_paths[$key] ? dirname($file_paths[$key]) : '';
+      $info['version'] = $this->getExtensionVersion($info);
+      return $info;
+    }, array_keys($infos), $infos);
+  }
+
+  /**
    * Get the extension version.
    *
-   * @param string $extension_name
-   *   The extension name.
    * @param array $info
    *   The extension's info.
    *
    * @return string|null
    *   The version or NULL if undefined.
    */
-  protected function getExtensionVersion($extension_name, array $info) {
+  protected function getExtensionVersion(array $info) {
+    $extension_name = $info['project'];
     if (isset($info['version']) && strpos($info['version'], '-dev') === FALSE) {
       return $info['version'];
     }
+    // Handle experimental modules from core.
+    if (substr($info['install path'], 0, 4 ) === "core") {
+      return $this->getExtensionList('module')->get('system')->info['version'];
+    }
     $composer_json = $this->getComposerJson($extension_name, $info);
     $extension_name = isset($composer_json['name']) ? $composer_json['name'] : $extension_name;
     try {
@@ -59,7 +101,6 @@
         $project_name = $this->getSuffix($composer_json['name'], '/', $extension_name);
       }
     }
-    // Handle one-off for Core.
     if ($project_name === 'system') {
       $project_name = 'drupal';
     }
diff -u b/src/Services/ModifiedFiles.php b/src/Services/ModifiedFiles.php
--- b/src/Services/ModifiedFiles.php
+++ b/src/Services/ModifiedFiles.php
@@ -72,6 +72,7 @@
    */
   public function getModifiedFiles(array $extensions = []) {
     $modified_files = [];
+    /** @var \GuzzleHttp\Promise\PromiseInterface[] $promises */
     $promises = $this->getHashRequests($extensions);
     // Wait until all the requests are finished.
     (new EachPromise($promises, [
@@ -86,13 +87,16 @@
   /**
    * Process checking hashes of files from external URL.
    *
-   * @param resource $resource
-   *   A resource handle.
+   * @param array $resource
+   *   An array of response resource and project info.
    * @param array $modified_files
    *   The list of modified files.
    */
-  protected function processHashes($resource, array &$modified_files) {
-    while (($line = fgets($resource)) !== FALSE) {
+  protected function processHashes(array $resource, array &$modified_files) {
+    $response = $resource['response'];
+    $info = $resource['info'];
+    $file_root = $info['install path'];
+    while (($line = fgets($response)) !== FALSE) {
       list($hash, $file) = preg_split('/\s+/', $line, 2);
       $file = trim($file);
       // If the line is empty, proceed to the next line.
@@ -107,15 +111,18 @@
       if ($this->isIgnoredPath($file)) {
         continue;
       }
-      $file_path = $this->drupalFinder->getDrupalRoot() . DIRECTORY_SEPARATOR . $file;
+      if ($info['project'] === 'drupal') {
+        $file_root = $this->drupalFinder->getDrupalRoot();
+      }
+      $file_path = $file_root . DIRECTORY_SEPARATOR . $file;
       if (!file_exists($file_path) || hash_file('sha512', $file_path) !== $hash) {
         $modified_files[] = $file_path;
       }
     }
-    if (!feof($resource)) {
+    if (!feof($response)) {
       $this->logger->error('Stream for resource closed prematurely.');
     }
-    fclose($resource);
+    fclose($response);
   }
 
   /**
@@ -131,9 +138,9 @@
    * @@codingStandardsIgnoreEnd
    */
   protected function getHashRequests(array $extensions) {
-    foreach ($extensions as $extension_name => $info) {
-      $url = $this->buildUrl($extension_name, $info);
-      yield $this->getPromise($url);
+    foreach ($extensions as $info) {
+      $url = $this->buildUrl($info);
+      yield $this->getPromise($url, $info);
     }
   }
 
@@ -142,34 +149,37 @@
    *
    * @param string $url
    *   The URL.
+   * @param array $info
+   *   The extension's info.
    *
    * @return \GuzzleHttp\Promise\PromiseInterface
    *   The promise.
    */
-  protected function getPromise($url) {
+  protected function getPromise($url, $info) {
     return $this->httpClient->requestAsync('GET', $url, [
       'stream' => TRUE,
       'read_timeout' => 30,
     ])
-      ->then(function (ResponseInterface $response) {
-        return $response->getBody()->detach();
+      ->then(function (ResponseInterface $response) use ($info) {
+        return [
+          'response' => $response->getBody()->detach(),
+          'info' => $info
+        ];
       });
   }
 
   /**
    * Build an extension's hash file URL.
    *
-   * @param string $extension_name
-   *   The extension name.
    * @param array $info
    *   The extension's info.
    *
    * @return string
    *   The URL endpoint with for an extension.
    */
-  protected function buildUrl($extension_name, array $info) {
-    $version = $this->getExtensionVersion($extension_name, $info);
-    $project_name = $this->getProjectName($extension_name, $info);
+  protected function buildUrl(array $info) {
+    $version = $info['version'];
+    $project_name = $info['project'];
     $hash_name = $this->getHashName($info);
     $uri = ltrim($this->configFactory->get('automatic_updates.settings')->get('hashes_uri'), '/');
     return Url::fromUri($uri . "/$project_name/$version/$hash_name")->toString();
@@ -186,7 +196,7 @@
    */
   protected function getHashName(array $info) {
     $hash_name = 'contents-sha512sums';
-    if (isset($info['project'])) {
+    if ($info['packaged']) {
       $hash_name .= '-packaged';
     }
     return $hash_name . '.txt';
only in patch2:
unchanged:
--- a/src/ReadinessChecker/MissingProjectInfo.php
+++ b/src/ReadinessChecker/MissingProjectInfo.php
@@ -72,12 +72,12 @@ class MissingProjectInfo extends Filesystem {
   protected function missingProjectInfoCheck() {
     $messages = [];
     foreach ($this->getExtensionsTypes() as $extension_type) {
-      foreach ($this->getInfos($extension_type) as $extension_name => $info) {
-        if ($this->isIgnoredPath(drupal_get_path($info['type'], $extension_name))) {
+      foreach ($this->getInfos($extension_type) as $info) {
+        if ($this->isIgnoredPath($info['install path'])) {
           continue;
         }
-        if (!$this->getExtensionVersion($extension_name, $info)) {
-          $messages[] = $this->t('The project "@extension" can not be updated because its version is either undefined or a dev release.', ['@extension' => $extension_name]);
+        if (!$info['version']) {
+          $messages[] = $this->t('The project "@extension" can not be updated because its version is either undefined or a dev release.', ['@extension' => $info['name']]);
         }
       }
     }
@@ -94,18 +94,4 @@ class MissingProjectInfo extends Filesystem {
     return ['modules', 'profiles', 'themes'];
   }
 
-  /**
-   * Returns an array of info files information of available extensions.
-   *
-   * @param string $extension_type
-   *   The extension type.
-   *
-   * @return array
-   *   An associative array of extension information arrays, keyed by extension
-   *   name.
-   */
-  protected function getInfos($extension_type) {
-    return $this->{$extension_type}->getAllAvailableInfo();
-  }
-
 }
only in patch2:
unchanged:
--- a/src/ReadinessChecker/ModifiedFiles.php
+++ b/src/ReadinessChecker/ModifiedFiles.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\automatic_updates\ReadinessChecker;
 
+use Drupal\automatic_updates\ProjectInfoTrait;
 use Drupal\automatic_updates\Services\ModifiedFilesInterface;
 use Drupal\Core\Extension\ExtensionList;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
@@ -11,6 +12,7 @@ use Drupal\Core\StringTranslation\StringTranslationTrait;
  */
 class ModifiedFiles implements ReadinessCheckerInterface {
   use StringTranslationTrait;
+  use ProjectInfoTrait;
 
   /**
    * The modified files service.
@@ -85,9 +87,9 @@ class ModifiedFiles implements ReadinessCheckerInterface {
     $extensions = [];
     $extensions['system'] = $this->modules->get('system')->info;
     foreach ($this->getExtensionsTypes() as $extension_type) {
-      foreach ($this->getInfos($extension_type) as $extension_name => $info) {
-        if (substr($this->getPath($extension_type, $extension_name), 0, 4) !== 'core') {
-          $extensions[$extension_name] = $info;
+      foreach ($this->getInfos($extension_type) as  $info) {
+        if (substr($info['install path'], 0, 4) !== 'core') {
+          $extensions[$info['project']] = $info;
         }
       }
     }
@@ -107,36 +109,4 @@ class ModifiedFiles implements ReadinessCheckerInterface {
     return ['modules', 'profiles', 'themes'];
   }
 
-  /**
-   * Returns an array of info files information of available extensions.
-   *
-   * @param string $extension_type
-   *   The extension type.
-   *
-   * @return array
-   *   An associative array of extension information arrays, keyed by extension
-   *   name.
-   */
-  protected function getInfos($extension_type) {
-    return $this->{$extension_type}->getAllAvailableInfo();
-  }
-
-  /**
-   * Returns an extension file path.
-   *
-   * @param string $extension_type
-   *   The extension type.
-   * @param string $extension_name
-   *   The extension name.
-   *
-   * @return string
-   *   An extension file path or NULL if it does not exist.
-   */
-  protected function getPath($extension_type, $extension_name) {
-    if (!isset($this->paths[$extension_type])) {
-      $this->paths[$extension_type] = $this->{$extension_type}->getPathnames();
-    }
-    return isset($this->paths[$extension_type][$extension_name]) ? $this->paths[$extension_type][$extension_name] : NULL;
-  }
-
 }
only in patch2:
unchanged:
--- a/tests/src/Kernel/ProjectInfoTraitTest.php
+++ b/tests/src/Kernel/ProjectInfoTraitTest.php
@@ -25,8 +25,8 @@ class ProjectInfoTraitTest extends KernelTestBase {
    */
   public function testTrait($expected, $info, $extension_name) {
     $class = new ProjectInfoTestClass();
-    $this->assertSame($expected['version'], $class->getExtensionVersion($extension_name, $info));
-    $this->assertSame($expected['project'], $class->getProjectName($extension_name, $info));
+    $this->assertSame($expected['version'], $class->getExtensionVersion($info));
+    $this->assertSame($expected['project'], $class->getProjectName($info));
   }
 
   /**
@@ -132,15 +132,15 @@ class ProjectInfoTestClass {
   /**
    * {@inheritdoc}
    */
-  public function getExtensionVersion($extension_name, array $info) {
-    return $this->getVersion($extension_name, $info);
+  public function getExtensionVersion(array $info) {
+    return $this->getVersion($info);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getProjectName($extension_name, array $info) {
-    return $this->getProject($extension_name, $info);
+  public function getProjectName(array $info) {
+    return $this->getProject($info);
   }
 
 }
