diff --git a/core/core.services.yml b/core/core.services.yml
index 276e19d..e2293fa 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -498,6 +498,9 @@ services:
       - { name: module_install.uninstall_validator }
     arguments: ['@string_translation']
     lazy: true
+  profile_handler:
+    class: Drupal\Core\Extension\ProfileHandler
+    arguments: ['@info_parser']
   theme_handler:
     class: Drupal\Core\Extension\ThemeHandler
     arguments: ['@app.root', '@config.factory', '@module_handler', '@state', '@info_parser']
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 1019270..8dda481 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -21,6 +21,7 @@
 use Drupal\Core\StringTranslation\Translator\FileTranslation;
 use Drupal\Core\StackMiddleware\ReverseProxyMiddleware;
 use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Extension\ProfileHandler;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Url;
 use Drupal\language\Entity\ConfigurableLanguage;
@@ -439,6 +440,10 @@ function install_begin_request($class_loader, &$install_state) {
     if (isset($install_state['profile_info']['distribution']['install']['theme'])) {
       $install_state['theme'] = $install_state['profile_info']['distribution']['install']['theme'];
     }
+    // Ensure all profile directories are registered.
+    $profile_handler = \Drupal::service('profile_handler');
+    $profile_directories = $profile_handler->getProfileDirectories($profile);
+    $listing->setProfileDirectories($profile_directories);
   }
 
   // Use the language from the profile configuration, if available, to override
@@ -1550,7 +1555,11 @@ function install_profile_themes(&$install_state) {
  *   An array of information about the current installation state.
  */
 function install_install_profile(&$install_state) {
-  \Drupal::service('module_installer')->install(array(drupal_get_profile()), FALSE);
+  $profile_handler = \Drupal::service('profile_handler');
+  $profiles = $profile_handler->getProfileDependencies(drupal_get_profile());
+
+  // Install all the profiles.
+  \Drupal::service('module_installer')->install($profiles, FALSE);
   // Install all available optional config. During installation the module order
   // is determined by dependencies. If there are no dependencies between modules
   // then the order in which they are installed is dependent on random factors
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 3a9c2bc..ae82e34 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\OpCodeCache;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Extension\ModuleHandler;
 use Drupal\Core\Site\Settings;
 
 /**
@@ -1029,6 +1030,12 @@ function drupal_check_module($module) {
  *   - install: Optional parameters to override the installer:
  *     - theme: The machine name of a theme to use in the installer instead of
  *       Drupal's default installer theme.
+ * - base_profile: Existence of this key denotes that the installation profile
+ *   depends on a parent installation profile.
+ *   - name: The shortname of the base installation profile.
+ *   - excluded_dependencies: An array of shortnames of other modules that have
+ *     to be excluded from the base profile requirements. This allows e.g. to
+ *     disable a demo module that would be installed by the base profile.
  *
  * Note that this function does an expensive file system scan to get info file
  * information for dependencies. If you only need information from the info
@@ -1073,6 +1080,25 @@ function install_profile_info($profile, $langcode = 'en') {
 
     $locale = !empty($langcode) && $langcode != 'en' ? array('locale') : array();
 
+    // Get the base profile chain.
+    if (!empty($info['base_profile']['name'])) {
+      $base_profile = install_profile_info($info['base_profile']['name'], $langcode);
+
+      // Ensure all dependencies are cleanly merged.
+      $info['dependencies'] = array_merge($info['dependencies'], $base_profile['dependencies']);
+      // If there are dependency excludes from the base apply them now.
+      if (!empty($info['base_profile']['excluded_dependencies'])) {
+        $info['dependencies'] = array_diff($info['dependencies'], $info['base_profile']['excluded_dependencies']);
+      }
+      // Ensure there's no circular dependency.
+      $info['dependencies'] = array_diff($info['dependencies'], array($profile));
+    }
+
+    // Ensure the same dependency notation as in modules can be used.
+    array_walk($info['dependencies'], function(&$dependency) {
+      $dependency = ModuleHandler::parseDependency($dependency)['name'];
+    });
+
     $info['dependencies'] = array_unique(array_merge($required, $info['dependencies'], $locale));
 
     $cache[$profile][$langcode] = $info;
diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php
index 97c3688..9c2ea5a 100644
--- a/core/lib/Drupal/Core/Config/ConfigInstaller.php
+++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
@@ -54,6 +54,13 @@ class ConfigInstaller implements ConfigInstallerInterface {
   protected $sourceStorage;
 
   /**
+   * ProfileHandler
+   *
+   * @var \Drupal\Core\Extension\ProfileHandler
+   */
+  protected $profileHandler;
+
+  /**
    * Is configuration being created as part of a configuration sync.
    *
    * @var bool
@@ -80,6 +87,7 @@ public function __construct(ConfigFactoryInterface $config_factory, StorageInter
     $this->typedConfig = $typed_config;
     $this->configManager = $config_manager;
     $this->eventDispatcher = $event_dispatcher;
+    $this->profileHandler = \Drupal::service('profile_handler');
   }
 
   /**
@@ -462,7 +470,7 @@ public function checkConfigurationToInstall($type, $name) {
 
     // Install profiles can not have config clashes. Configuration that
     // has the same name as a module's configuration will be used instead.
-    if ($name != $this->drupalGetProfile()) {
+    if (!$this->profileHandler->isProfile($name)) {
       // Throw an exception if the module being installed contains configuration
       // that already exists. Additionally, can not continue installing more
       // modules because those may depend on the current module being installed.
diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
index 0d9283c..d5be261 100644
--- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
+++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Extension\Discovery\RecursiveExtensionFilterIterator;
 use Drupal\Core\Site\Settings;
 use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Extension\ProfileHandler;
 
 /**
  * Discovers available extensions in the filesystem.
@@ -248,8 +249,10 @@ public function setProfileDirectoriesFromSettings() {
     // In case both profile directories contain the same extension, the actual
     // profile always has precedence.
     if ($profile) {
-      $this->profileDirectories[] = drupal_get_path('profile', $profile);
+      $profile_handler = \Drupal::service('profile_handler');
+      $this->profileDirectories = array_merge($profile_handler->getProfileDirectories($profile), $this->profileDirectories);
     }
+
     return $this;
   }
 
diff --git a/core/lib/Drupal/Core/Extension/ProfileHandler.php b/core/lib/Drupal/Core/Extension/ProfileHandler.php
new file mode 100644
index 0000000..90e9ed9
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/ProfileHandler.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\Core\Extension;
+
+use Drupal\Core\Site\Settings;
+
+/**
+ * Class that manages profiles in a Drupal installation.
+ */
+class ProfileHandler {
+
+  /**
+   * Static state cache.
+   *
+   * @var array
+   */
+  protected static $cache = array();
+
+  /**
+   * The info parser to parse the profile.info.yml files.
+   *
+   * @var \Drupal\Core\Extension\InfoParserInterface
+   */
+  protected $infoParser;
+
+  /**
+   * Constructs a new ProfileHandler.
+   *
+   * @param \Drupal\Core\Extension\InfoParserInterface $info_parser
+   *   The info parser to parse the profile.info.yml files.
+   */
+  public function __construct(InfoParserInterface $info_parser) {
+    $this->infoParser = $info_parser;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getProfileDependencies($profile) {
+    if (!isset(static::$cache[$profile])) {
+      $profiles = array();
+      // Check if a valid profile name was given.
+      if (!empty($profile)) {
+        // We can't use install_profile_info() because that could trigger an
+        // endless loop. So we read this on our own.
+        $profile_file = drupal_get_path('profile', $profile) . "/$profile.info.yml";
+        $profile_info = $this->infoParser->parse($profile_file);
+
+        // Check of the profile has a base profile and if so add it - recursion.
+        if (!empty($profile_info['base_profile']['name']) && !isset($profiles[$profile_info['base_profile']['name']])) {
+          $profiles += $this->getProfileDependencies($profile_info['base_profile']['name']);
+        }
+        // Add requested profile as last one.
+        $profiles[$profile] = $profile;
+      }
+      static::$cache[$profile] = $profiles;
+    }
+    return static::$cache[$profile];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getProfileDirectories($profile) {
+    $profile_directories = array();
+    foreach ($this->getProfileDependencies($profile) as $profile_dependency => $profile_dependency_info) {
+      $profile_directories[] = drupal_get_path('profile', $profile_dependency);
+    }
+    return $profile_directories;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isProfile($profile) {
+    $current_profile = drupal_get_profile();
+    $base_profiles = $this->getProfileDependencies($current_profile);
+    return isset($base_profiles[$profile]);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php b/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php
new file mode 100644
index 0000000..3b63775
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\Core\Extension;
+
+/**
+ * Interface for classes that manage profiles.
+ */
+interface ProfileHandlerInterface {
+
+  /**
+   * Returns a list of related installation profiles.
+   *
+   * @param $profile
+   *   Name of profile.
+   *
+   * @return array
+   *   List of dependent installation profiles in descending order of their
+   *   dependencies.
+   */
+  public function getProfileDependencies($profile);
+
+  /**
+   * Returns an array of install profile directories
+   *
+   * @param $profile
+   *   Name of profile.
+   *
+   * @return array
+   *   List of profile paths
+   */
+  public function getProfileDirectories($profile);
+
+  /**
+   * Returns whether the given extension name is an install profile,
+   * including base profiles
+   *
+   * @param $profile
+   *   Name of profile.
+   *
+   * @return bool
+   */
+  public function isProfile($profile);
+
+}
