 core/MAINTAINERS.txt                               |  3 +
 core/composer.json                                 |  1 +
 .../modules/automated_cron/automated_cron.info.yml |  6 ++
 core/modules/automated_cron/automated_cron.module  | 74 +++++++++++++++++
 .../automated_cron/automated_cron.services.yml     |  6 ++
 .../config/install/automated_cron.settings.yml     |  1 +
 .../config/schema/automated_cron.schema.yml        |  9 +++
 .../src/EventSubscriber/AutomatedCron.php          | 85 ++++++++++++++++++++
 .../src/Tests/ConfigInstallProfileOverrideTest.php |  2 -
 .../config/install/system.cron.yml                 |  1 -
 .../src/Tests/SearchMultilingualEntityTest.php     |  3 -
 core/modules/system/config/install/system.cron.yml |  1 -
 .../modules/system/config/schema/system.schema.yml |  3 -
 .../system/src/EventSubscriber/AutomaticCron.php   | 92 ----------------------
 core/modules/system/src/Form/CronForm.php          | 64 ++++++---------
 .../system/src/Tests/System/CronRunTest.php        | 28 +++----
 .../AutomatedCronUpdateWithAutomatedCronTest.php   | 36 +++++++++
 ...AutomatedCronUpdateWithoutAutomatedCronTest.php | 36 +++++++++
 .../system/src/Tests/Update/UpdatePathTestBase.php |  1 +
 core/modules/system/system.install                 | 22 ++++++
 core/modules/system/system.module                  |  2 +-
 core/modules/system/system.services.yml            |  5 --
 .../update/drupal-8.without_automated_cron.php     | 14 ++++
 .../config/install/automated_cron.settings.yml     |  1 +
 .../standard/config/install/system.cron.yml        |  1 -
 core/profiles/standard/standard.info.yml           |  1 +
 .../config/install/system.cron.yml                 |  1 -
 27 files changed, 334 insertions(+), 165 deletions(-)

diff --git a/core/MAINTAINERS.txt b/core/MAINTAINERS.txt
index f0527c3..315ba2e 100644
--- a/core/MAINTAINERS.txt
+++ b/core/MAINTAINERS.txt
@@ -256,6 +256,9 @@ Action module
 Aggregator module
 - Paris Liakos 'ParisLiakos' https://www.drupal.org/u/parisliakos
 
+Automated Cron module
+- ?
+
 Ban module
 - ?
 
diff --git a/core/composer.json b/core/composer.json
index 49842ba..2489069 100644
--- a/core/composer.json
+++ b/core/composer.json
@@ -41,6 +41,7 @@
   "replace": {
     "drupal/action": "self.version",
     "drupal/aggregator": "self.version",
+    "drupal/automated_cron": "self.version",
     "drupal/bartik": "self.version",
     "drupal/ban": "self.version",
     "drupal/basic_auth": "self.version",
diff --git a/core/modules/automated_cron/automated_cron.info.yml b/core/modules/automated_cron/automated_cron.info.yml
new file mode 100644
index 0000000..a7480e9
--- /dev/null
+++ b/core/modules/automated_cron/automated_cron.info.yml
@@ -0,0 +1,6 @@
+name: 'Automated Cron'
+type: module
+description: 'Provides an automated way to run cron jobs, by executing them at the end of a server response.'
+package: Core
+version: VERSION
+core: 8.x
diff --git a/core/modules/automated_cron/automated_cron.module b/core/modules/automated_cron/automated_cron.module
new file mode 100644
index 0000000..2c1552d
--- /dev/null
+++ b/core/modules/automated_cron/automated_cron.module
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Provides an automated cron by executing it at the end of a response.
+ */
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Implements hook_help().
+ */
+function automated_cron_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.automated_cron':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Automated Cron module runs cron operations for your site using normal browser/page requests instead of having to set up a separate cron job. The Automated Cron module checks at the end of each server response when cron operation was last ran and, if it has been too long since last run, it executes the cron tasks after sending a server response. For more information, see the <a href=":automated_cron-documentation">online documentation for the Dynamic Page Cache module</a>.', [':automated_cron-documentation' => 'https://www.drupal.org/documentation/modules/automated_cron'])  . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Configuring Automated Cron') . '</dt>';
+      $output .= '<dd>' . t('On the <a href=":cron-settings">Cron page</a>, you can set the frequency (time interval) for running cron jobs.', [':cron-settings' => \Drupal::url('system.cron_settings')])  . '</dd>';
+      $output .= '<dt>' . t('Disabling Automated Cron') . '</dt>';
+      $output .= '<dd>' . t('To disable automated cron, the recommended method is to uninstall the module, to reduce site overhead. If you only want to disable it temporarily, you can set the frequency to Never on the Cron page, and then change the frequency back when you want to start it up again.')  . '</dd>';
+      $output .= '</dl>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for the system_cron_settings() form.
+ */
+function automated_cron_form_system_cron_settings_alter(&$form, &$form_state) {
+  $automated_cron_settings = \Drupal::config('automated_cron.settings');
+
+  // Add automated cron settings.
+  $form['automated_cron'] = [
+    '#title' => t('Cron settings'),
+    '#type' => 'details',
+    '#open' => TRUE,
+  ];
+  $options = [3600, 10800, 21600, 43200, 86400, 604800];
+  $form['automated_cron']['interval'] = [
+    '#type' => 'select',
+    '#title' => t('Run cron every'),
+    '#description' => t('More information about setting up scheduled tasks can be found by <a href="@url">reading the cron tutorial on drupal.org</a>.', ['@url' => 'https://www.drupal.org/cron']),
+    '#default_value' => $automated_cron_settings->get('interval'),
+    '#options' => [0 => t('Never')] + array_map([\Drupal::service('date.formatter'), 'formatInterval'], array_combine($options, $options)),
+  ];
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['submit'] = [
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+    '#button_type' => 'primary',
+  ];
+
+  // Add submit callback.
+  $form['#submit'][] = 'automated_cron_settings_submit';
+
+  // Theme this form as a config form.
+  $form['#theme'] = 'system_config_form';
+}
+
+/**
+ * Form submission handler for system_cron_settings().
+ */
+function automated_cron_settings_submit(array $form, FormStateInterface $form_state) {
+  \Drupal::configFactory()->getEditable('automated_cron.settings')
+    ->set('interval', $form_state->getValue('interval'))
+    ->save();
+  drupal_set_message(t('The configuration options have been saved.'));
+}
diff --git a/core/modules/automated_cron/automated_cron.services.yml b/core/modules/automated_cron/automated_cron.services.yml
new file mode 100644
index 0000000..6bc3c00
--- /dev/null
+++ b/core/modules/automated_cron/automated_cron.services.yml
@@ -0,0 +1,6 @@
+services:
+  automated_cron.subscriber:
+    class: Drupal\automated_cron\EventSubscriber\AutomatedCron
+    arguments: ['@cron', '@config.factory', '@state']
+    tags:
+      - { name: event_subscriber }
diff --git a/core/modules/automated_cron/config/install/automated_cron.settings.yml b/core/modules/automated_cron/config/install/automated_cron.settings.yml
new file mode 100644
index 0000000..963bd71
--- /dev/null
+++ b/core/modules/automated_cron/config/install/automated_cron.settings.yml
@@ -0,0 +1 @@
+interval: 10800
diff --git a/core/modules/automated_cron/config/schema/automated_cron.schema.yml b/core/modules/automated_cron/config/schema/automated_cron.schema.yml
new file mode 100644
index 0000000..b808d80
--- /dev/null
+++ b/core/modules/automated_cron/config/schema/automated_cron.schema.yml
@@ -0,0 +1,9 @@
+# Schema for the configuration files of the Automated cron module.
+
+automated_cron.settings:
+  type: config_object
+  label: 'Automated cron settings'
+  mapping:
+    interval:
+      type: integer
+      label: 'Run cron every'
diff --git a/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php b/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php
new file mode 100644
index 0000000..5b26919
--- /dev/null
+++ b/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\automated_cron\EventSubscriber\AutomatedCron.
+ */
+
+namespace Drupal\automated_cron\EventSubscriber;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\CronInterface;
+use Drupal\Core\State\StateInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Event\PostResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * A subscriber running cron after a response is sent.
+ */
+class AutomatedCron implements EventSubscriberInterface {
+
+  /**
+   * The cron service.
+   *
+   * @var \Drupal\Core\CronInterface
+   */
+  protected $cron;
+
+  /**
+   * The cron configuration.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $config;
+
+  /**
+   * The state key value store.
+   *
+   * @var \Drupal\Core\State\StateInterface;
+   */
+  protected $state;
+
+  /**
+   * Constructs a new automated cron runner.
+   *
+   * @param \Drupal\Core\CronInterface $cron
+   *   The cron service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state key-value store service.
+   */
+  public function __construct(CronInterface $cron, ConfigFactoryInterface $config_factory, StateInterface $state) {
+    $this->cron = $cron;
+    $this->config = $config_factory->get('automated_cron.settings');
+    $this->state = $state;
+  }
+
+  /**
+   * Run the automated cron if enabled.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\PostResponseEvent $event
+   *   The Event to process.
+   */
+  public function onTerminate(PostResponseEvent $event) {
+    $interval = $this->config->get('interval');
+    if ($interval > 0) {
+      $cron_next = $this->state->get('system.cron_last', 0) + $interval;
+      if ((int) $event->getRequest()->server->get('REQUEST_TIME') > $cron_next) {
+        $this->cron->run();
+      }
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  public static function getSubscribedEvents() {
+    return [KernelEvents::TERMINATE => [['onTerminate', 100]]];
+  }
+
+}
diff --git a/core/modules/config/src/Tests/ConfigInstallProfileOverrideTest.php b/core/modules/config/src/Tests/ConfigInstallProfileOverrideTest.php
index 4c71e85..b5409be 100644
--- a/core/modules/config/src/Tests/ConfigInstallProfileOverrideTest.php
+++ b/core/modules/config/src/Tests/ConfigInstallProfileOverrideTest.php
@@ -37,7 +37,6 @@ function testInstallProfileConfigOverwrite() {
     // The expected configuration from the system module.
     $expected_original_data = array(
       'threshold' => array(
-        'autorun' => 0,
         'requirements_warning' => 172800,
         'requirements_error' => 1209600,
       ),
@@ -45,7 +44,6 @@ function testInstallProfileConfigOverwrite() {
     // The expected active configuration altered by the install profile.
     $expected_profile_data = array(
       'threshold' => array(
-        'autorun' => 0,
         'requirements_warning' => 259200,
         'requirements_error' => 1209600,
       ),
diff --git a/core/modules/config/tests/config_override_test/config/install/system.cron.yml b/core/modules/config/tests/config_override_test/config/install/system.cron.yml
index 79f797f..e4a27dc 100644
--- a/core/modules/config/tests/config_override_test/config/install/system.cron.yml
+++ b/core/modules/config/tests/config_override_test/config/install/system.cron.yml
@@ -1,5 +1,4 @@
 threshold:
-  autorun: 0
   requirements_warning: 172800
   requirements_error: 1209600
 
diff --git a/core/modules/search/src/Tests/SearchMultilingualEntityTest.php b/core/modules/search/src/Tests/SearchMultilingualEntityTest.php
index f924de8..4a85ee4 100644
--- a/core/modules/search/src/Tests/SearchMultilingualEntityTest.php
+++ b/core/modules/search/src/Tests/SearchMultilingualEntityTest.php
@@ -41,9 +41,6 @@ protected function setUp() {
     $user = $this->drupalCreateUser(array('administer search', 'search content', 'use advanced search', 'access content', 'access site reports', 'administer site configuration'));
     $this->drupalLogin($user);
 
-    // Make sure that auto-cron is disabled.
-    $this->config('system.cron')->set('threshold.autorun', 0)->save();
-
     // Set up the search plugin.
     $this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
 
diff --git a/core/modules/system/config/install/system.cron.yml b/core/modules/system/config/install/system.cron.yml
index 5cf7ee6..e6f30d3 100644
--- a/core/modules/system/config/install/system.cron.yml
+++ b/core/modules/system/config/install/system.cron.yml
@@ -1,4 +1,3 @@
 threshold:
-  autorun: 0
   requirements_warning: 172800
   requirements_error: 1209600
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index b4a8873..e34d375 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -66,9 +66,6 @@ system.cron:
       type: mapping
       label: 'Thresholds'
       mapping:
-        autorun:
-          type: integer
-          label: 'Run cron every'
         requirements_warning:
           type: integer
           label: 'Requirements warning period'
diff --git a/core/modules/system/src/EventSubscriber/AutomaticCron.php b/core/modules/system/src/EventSubscriber/AutomaticCron.php
deleted file mode 100644
index 3b630df..0000000
--- a/core/modules/system/src/EventSubscriber/AutomaticCron.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\EventSubscriber\AutomaticCron.
- */
-
-namespace Drupal\system\EventSubscriber;
-
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\CronInterface;
-use Drupal\Core\State\StateInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\Event\PostResponseEvent;
-use Symfony\Component\HttpKernel\KernelEvents;
-
-/**
- * A subscriber running cron when a request terminates.
- */
-class AutomaticCron implements EventSubscriberInterface {
-
-  /**
-   * The cron service.
-   *
-   * @var \Drupal\Core\CronInterface
-   */
-  protected $cron;
-
-  /**
-   * The cron configuration.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected $config;
-
-  /**
-   * The state key value store.
-   *
-   * Drupal\Core\State\StateInterface;
-   */
-  protected $state;
-
-  /**
-   * Construct a new automatic cron runner.
-   *
-   * @param \Drupal\Core\CronInterface $cron
-   *   The cron service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory.
-   * @param \Drupal\Core\State\StateInterface $state
-   *   The state key value store.
-   */
-  public function __construct(CronInterface $cron, ConfigFactoryInterface $config_factory, StateInterface $state) {
-    $this->cron = $cron;
-    $this->config = $config_factory->get('system.cron');
-    $this->state = $state;
-  }
-
-  /**
-   * Run the automated cron if enabled.
-   *
-   * @param Symfony\Component\HttpKernel\Event\PostResponseEvent $event
-   *   The Event to process.
-   */
-  public function onTerminate(PostResponseEvent $event) {
-    // If the site is not fully installed, suppress the automated cron run.
-    // Otherwise it could be triggered prematurely by Ajax requests during
-    // installation.
-    if ($this->state->get('install_task') == 'done') {
-      $threshold = $this->config->get('threshold.autorun');
-      if ($threshold > 0) {
-        $cron_next = $this->state->get('system.cron_last', 0) + $threshold;
-        if (REQUEST_TIME > $cron_next) {
-          $this->cron->run();
-        }
-      }
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
-   */
-  public static function getSubscribedEvents() {
-    $events[KernelEvents::TERMINATE][] = array('onTerminate', 100);
-
-    return $events;
-  }
-
-}
diff --git a/core/modules/system/src/Form/CronForm.php b/core/modules/system/src/Form/CronForm.php
index 8d9545c..5fec62f 100644
--- a/core/modules/system/src/Form/CronForm.php
+++ b/core/modules/system/src/Form/CronForm.php
@@ -10,16 +10,17 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\CronInterface;
 use Drupal\Core\Datetime\DateFormatterInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
-use Drupal\Core\Form\ConfigFormBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Configure cron settings for this site.
  */
-class CronForm extends ConfigFormBase {
+class CronForm extends FormBase {
 
   /**
    * Stores the state storage service.
@@ -43,6 +44,13 @@ class CronForm extends ConfigFormBase {
   protected $dateFormatter;
 
   /**
+   * The module handler service.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
+   */
+  protected $moduleHandler;
+
+  /**
    * Constructs a CronForm object.
    *
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
@@ -53,12 +61,14 @@ class CronForm extends ConfigFormBase {
    *   The cron service.
    * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
    *   The date formatter service.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler service.
    */
-  public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, CronInterface $cron, DateFormatterInterface $date_formatter) {
-    parent::__construct($config_factory);
+  public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, CronInterface $cron, DateFormatterInterface $date_formatter, ModuleHandlerInterface $module_handler) {
     $this->state = $state;
     $this->cron = $cron;
     $this->dateFormatter = $date_formatter;
+    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -69,7 +79,8 @@ public static function create(ContainerInterface $container) {
       $container->get('config.factory'),
       $container->get('state'),
       $container->get('cron'),
-      $container->get('date.formatter')
+      $container->get('date.formatter'),
+      $container->get('module_handler')
     );
   }
 
@@ -83,23 +94,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  protected function getEditableConfigNames() {
-    return ['system.cron'];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    $config = $this->config('system.cron');
-
     $form['description'] = array(
       '#markup' => '<p>' . t('Cron takes care of running periodic tasks like checking for updates and indexing content for search.') . '</p>',
     );
     $form['run'] = array(
       '#type' => 'submit',
       '#value' => t('Run cron'),
-      '#submit' => array('::submitCron'),
     );
     $status = '<p>' . $this->t('Last run: %time ago.', array('%time' => $this->dateFormatter->formatTimeDiffSince($this->state->get('system.cron_last')))) . '</p>';
     $form['status'] = array(
@@ -111,38 +112,19 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#markup' => '<p>' . t('To run cron from outside the site, go to <a href=":cron">@cron</a>', array(':cron' => $cron_url, '@cron' => $cron_url)) . '</p>',
     );
 
-    $form['cron'] = array(
-      '#title' => t('Cron settings'),
-      '#type' => 'details',
-      '#open' => TRUE,
-    );
-    $options = array(3600, 10800, 21600, 43200, 86400, 604800);
-    $form['cron']['cron_safe_threshold'] = array(
-      '#type' => 'select',
-      '#title' => t('Run cron every'),
-      '#description' => t('More information about setting up scheduled tasks can be found by <a href=":url">reading the cron tutorial on drupal.org</a>.', array(':url' => 'https://www.drupal.org/cron')),
-      '#default_value' => $config->get('threshold.autorun'),
-      '#options' => array(0 => t('Never')) + array_map(array($this->dateFormatter, 'formatInterval'), array_combine($options, $options)),
-    );
-
-    return parent::buildForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $this->config('system.cron')
-      ->set('threshold.autorun', $form_state->getValue('cron_safe_threshold'))
-      ->save();
+    if (!$this->moduleHandler->moduleExists('automated_cron')) {
+      $form['cron'] = array(
+        '#markup' => $this->t('Enable the <em>Automated Cron</em> module to allow cron execution at the end of a server response.'),
+      );
+    }
 
-    parent::submitForm($form, $form_state);
+    return $form;
   }
 
   /**
    * Runs cron and reloads the page.
    */
-  public function submitCron(array &$form, FormStateInterface $form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state) {
     // Run cron manually from Cron form.
     if ($this->cron->run()) {
       drupal_set_message(t('Cron run successfully.'));
diff --git a/core/modules/system/src/Tests/System/CronRunTest.php b/core/modules/system/src/Tests/System/CronRunTest.php
index 063d9ab..e39e919 100644
--- a/core/modules/system/src/Tests/System/CronRunTest.php
+++ b/core/modules/system/src/Tests/System/CronRunTest.php
@@ -21,7 +21,7 @@ class CronRunTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('common_test', 'common_test_cron_helper');
+  public static $modules = ['common_test', 'common_test_cron_helper', 'automated_cron'];
 
   /**
    * Test cron runs.
@@ -43,42 +43,42 @@ function testCronRun() {
   }
 
   /**
-   * Ensure that the automatic cron run feature is working.
+   * Ensure that the automated cron run module is working.
    *
    * In these tests we do not use REQUEST_TIME to track start time, because we
    * need the exact time when cron is triggered.
    */
-  function testAutomaticCron() {
+  function testAutomatedCron() {
     // Test with a logged in user; anonymous users likely don't cause Drupal to
     // fully bootstrap, because of the internal page cache or an external
     // reverse proxy. Reuse this user for disabling cron later in the test.
     $admin_user = $this->drupalCreateUser(array('administer site configuration'));
     $this->drupalLogin($admin_user);
 
-    // Ensure cron does not run when the cron threshold is enabled and was
-    // not passed.
+    // Ensure cron does not run when a non-zero cron interval is specified and
+    // was not passed.
     $cron_last = time();
-    $cron_safe_threshold = 100;
+    $cron_safe_interval = 100;
     \Drupal::state()->set('system.cron_last', $cron_last);
-    $this->config('system.cron')
-      ->set('threshold.autorun', $cron_safe_threshold)
+    $this->config('automated_cron.settings')
+      ->set('interval', $cron_safe_interval)
       ->save();
     $this->drupalGet('');
-    $this->assertTrue($cron_last == \Drupal::state()->get('system.cron_last'), 'Cron does not run when the cron threshold is not passed.');
+    $this->assertTrue($cron_last == \Drupal::state()->get('system.cron_last'), 'Cron does not run when the cron interval is not passed.');
 
-    // Test if cron runs when the cron threshold was passed.
+    // Test if cron runs when the cron interval was passed.
     $cron_last = time() - 200;
     \Drupal::state()->set('system.cron_last', $cron_last);
     $this->drupalGet('');
     sleep(1);
-    $this->assertTrue($cron_last < \Drupal::state()->get('system.cron_last'), 'Cron runs when the cron threshold is passed.');
+    $this->assertTrue($cron_last < \Drupal::state()->get('system.cron_last'), 'Cron runs when the cron interval is passed.');
 
-    // Disable the cron threshold through the interface.
-    $this->drupalPostForm('admin/config/system/cron', array('cron_safe_threshold' => 0), t('Save configuration'));
+    // Disable cron through the interface by setting the interval to zero.
+    $this->drupalPostForm('admin/config/system/cron', ['interval' => 0], t('Save configuration'));
     $this->assertText(t('The configuration options have been saved.'));
     $this->drupalLogout();
 
-    // Test if cron does not run when the cron threshold is disabled.
+    // Test if cron does not run when the cron interval is set to zero.
     $cron_last = time() - 200;
     \Drupal::state()->set('system.cron_last', $cron_last);
     $this->drupalGet('');
diff --git a/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithAutomatedCronTest.php b/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithAutomatedCronTest.php
new file mode 100644
index 0000000..ace302c
--- /dev/null
+++ b/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithAutomatedCronTest.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Update\AutomatedCronUpdateWithAutomatedCronTest.
+ */
+
+namespace Drupal\system\Tests\Update;
+
+/**
+ * Ensures that the automated cron module is installed on update.
+ *
+ * @group Update
+ */
+class AutomatedCronUpdateWithAutomatedCronTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+    ];
+  }
+
+  /**
+   * Ensures that automated cron module isn installed and the config migrated.
+   */
+  public function testUpdate() {
+    $this->runUpdates();
+
+    $module_data = \Drupal::config('core.extension')->get('module');
+    $this->assertTrue(isset($module_data['automated_cron']), 'The automated cron module was installed.');
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php b/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
new file mode 100644
index 0000000..d55a8b2
--- /dev/null
+++ b/core/modules/system/src/Tests/Update/AutomatedCronUpdateWithoutAutomatedCronTest.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Update\AutomatedCronUpdateWithoutAutomatedCronTest.
+ */
+
+namespace Drupal\system\Tests\Update;
+
+/**
+ * Ensures that the automated cron module is not installed on update.
+ *
+ * @group Update
+ */
+class AutomatedCronUpdateWithoutAutomatedCronTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+      __DIR__ . '/../../../tests/fixtures/update/drupal-8.without_automated_cron.php',
+    ];
+  }
+
+  /**
+   * Ensures that automated cron module isn't installed and the config migrated.
+   */
+  public function testUpdate() {
+    $this->runUpdates();
+    $module_data = \Drupal::config('core.extension')->get('module');
+    $this->assertFalse(isset($module_data['automated_cron']), 'The automated cron module was not installed.');
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
index 5fae5a0..e5780a1 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -263,6 +263,7 @@ protected function runUpdates() {
     $names = $this->container->get('config.storage')->listAll();
     /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
     $typed_config = $this->container->get('config.typed');
+    $typed_config->clearCachedDefinitions();
     foreach ($names as $name) {
       $config = $this->config($name);
       $this->assertConfigSchema($typed_config, $name, $config->get());
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 47f6dca..0972661 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1808,5 +1808,27 @@ function system_update_8011() {
 }
 
 /**
+ * Enable automated cron module and move the config into it.
+ */
+function system_update_8012() {
+  $config_factory = \Drupal::configFactory();
+  $system_cron_config = $config_factory->getEditable('system.cron');
+  if ($autorun = $system_cron_config->get('threshold.autorun')) {
+    // Install 'automated_cron' module.
+    \Drupal::service('module_installer')->install(['automated_cron'], FALSE);
+
+    // Copy 'autorun' value into the new module's 'interval' setting.
+    $config_factory->getEditable('automated_cron.settings')
+      ->set('interval', $autorun)
+      ->save(TRUE);
+  }
+
+  // Remove the 'autorun' key in system module config.
+  $system_cron_config
+    ->clear('threshold.autorun')
+    ->save(TRUE);
+}
+
+/**
  * @} End of "addtogroup updates-8.0.0-beta".
  */
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 3d9f129..ce3eddc 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -96,7 +96,7 @@ function system_help($route_name, RouteMatchInterface $route_match) {
       $output .= '<dt>' . t('Configuring for performance') . '</dt>';
       $output .= '<dd>' . t('On the <a href=":performance-page">Performance page</a>, the site can be configured to aggregate CSS and JavaScript files, making the total request size smaller. Note that, for small- to medium-sized websites, the <a href=":page-cache">Internal Page Cache module</a> should be installed so that pages are efficiently cached and reused for anonymous users. Finally, for websites of all sizes, the <a href=":dynamic-page-cache">Dynamic Page Cache module</a> should also be installed so that the non-personalized parts of pages are efficiently cached (for all users).', array(':performance-page' => \Drupal::url('system.performance_settings'), ':page-cache' => (\Drupal::moduleHandler()->moduleExists('page_cache')) ? \Drupal::url('help.page', array('name' => 'page_cache')) : '#', ':dynamic-page-cache' => (\Drupal::moduleHandler()->moduleExists('dynamic_page_cache')) ? \Drupal::url('help.page', array('name' => 'dynamic_page_cache')) : '#')) . '</dd>';
       $output .= '<dt>' . t('Configuring cron') . '</dt>';
-      $output .= '<dd>' . t('In order for the site and its modules to continue to operate well, a set of routine administrative operations must run on a regular basis; these operations are known as <em>cron</em> tasks. On the <a href=":cron">Cron page</a>, you can configure cron to run periodically as part of normal page requests, or you can turn this off and trigger cron from an outside process on your web server. You can verify the status of cron tasks by visiting the <a href=":status">Status report page</a>. For more information, see the <a href=":handbook">online documentation for configuring cron jobs</a>.', array(':status' => \Drupal::url('system.status'), ':handbook' => 'https://www.drupal.org/cron', ':cron' => \Drupal::url('system.cron_settings'))) . '</dd>';
+      $output .= '<dd>' . t('In order for the site and its modules to continue to operate well, a set of routine administrative operations must run on a regular basis; these operations are known as <em>cron</em> tasks. On the <a href=":cron">Cron page</a>, you can configure cron to run periodically as part of server responses by installing the <em>Automated Cron</em> module, or you can turn this off and trigger cron from an outside process on your web server. You can verify the status of cron tasks by visiting the <a href=":status">Status report page</a>. For more information, see the <a href=":handbook">online documentation for configuring cron jobs</a>.', array(':status' => \Drupal::url('system.status'), ':handbook' => 'https://www.drupal.org/cron', ':cron' => \Drupal::url('system.cron_settings'))) . '</dd>';
       $output .= '<dt>' . t('Configuring the file system') . '</dt>';
       $output .= '<dd>' . t('Your site has several file directories, which are used to store and process uploaded and generated files. The <em>public</em> file directory, which is configured in your settings.php file, is the default place for storing uploaded files. Links to files in this directory contain the direct file URL, so when the files are requested, the web server will send them directly without invoking your site code. This means that the files can be downloaded by anyone with the file URL, so requests are not access-controlled but they are efficient. The <em>private</em> file directory, also configured in your settings.php file and ideally located outside the site web root, is access controlled. Links to files in this directory are not direct, so requests to these files are mediated by your site code. This means that your site can check file access permission for each file before deciding to fulfill the request, so the requests are more secure, but less efficient. You should only use the private storage for files that need access control, not for files like your site logo and background images used on every page. The <em>temporary</em> file directory is used internally by your site code for various operations, and is configured on the <a href=":file-system">File system settings</a> page. You can also see the configured public and private file directories on this page, and choose whether public or private should be the default for uploaded files.', array(':file-system' => \Drupal::url('system.file_system_settings'))) . '</dd>';
       $output .= '<dt>' . t('Configuring the image toolkit') . '</dt>';
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 29ea018..0f816d6 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -37,11 +37,6 @@ services:
     class: Drupal\system\SystemConfigSubscriber
     tags:
       - { name: event_subscriber }
-  system.automatic_cron:
-    class: Drupal\system\EventSubscriber\AutomaticCron
-    arguments: ['@cron', '@config.factory', '@state']
-    tags:
-      - { name: event_subscriber }
   system.config_cache_tag:
     class: Drupal\system\EventSubscriber\ConfigCacheTag
     arguments: ['@theme_handler', '@cache_tags.invalidator']
diff --git a/core/modules/system/tests/fixtures/update/drupal-8.without_automated_cron.php b/core/modules/system/tests/fixtures/update/drupal-8.without_automated_cron.php
new file mode 100644
index 0000000..81e4e72
--- /dev/null
+++ b/core/modules/system/tests/fixtures/update/drupal-8.without_automated_cron.php
@@ -0,0 +1,14 @@
+<?php
+
+$connection = Drupal\Core\Database\Database::getConnection();
+$config = $connection;
+
+$connection->merge('config')
+  ->condition('name', 'system.cron')
+  ->condition('collection', '')
+  ->fields([
+    'name' => 'system.cron',
+    'collection' => '',
+    'data' => serialize(['threshold' => ['autorun' => 0]]),
+  ])
+  ->execute();
diff --git a/core/profiles/standard/config/install/automated_cron.settings.yml b/core/profiles/standard/config/install/automated_cron.settings.yml
new file mode 100644
index 0000000..963bd71
--- /dev/null
+++ b/core/profiles/standard/config/install/automated_cron.settings.yml
@@ -0,0 +1 @@
+interval: 10800
diff --git a/core/profiles/standard/config/install/system.cron.yml b/core/profiles/standard/config/install/system.cron.yml
index 9289f28..e6f30d3 100644
--- a/core/profiles/standard/config/install/system.cron.yml
+++ b/core/profiles/standard/config/install/system.cron.yml
@@ -1,4 +1,3 @@
 threshold:
-  autorun: 10800
   requirements_warning: 172800
   requirements_error: 1209600
diff --git a/core/profiles/standard/standard.info.yml b/core/profiles/standard/standard.info.yml
index 9851f9b..82af32e 100644
--- a/core/profiles/standard/standard.info.yml
+++ b/core/profiles/standard/standard.info.yml
@@ -37,6 +37,7 @@ dependencies:
   - views
   - views_ui
   - tour
+  - automated_cron
 themes:
   - bartik
   - seven
diff --git a/core/profiles/testing_config_overrides/config/install/system.cron.yml b/core/profiles/testing_config_overrides/config/install/system.cron.yml
index 38b0d88..e9c97bc 100644
--- a/core/profiles/testing_config_overrides/config/install/system.cron.yml
+++ b/core/profiles/testing_config_overrides/config/install/system.cron.yml
@@ -1,4 +1,3 @@
 threshold:
-  autorun: 0
   requirements_warning: 259200
   requirements_error: 1209600
