diff --git a/core/core.services.yml b/core/core.services.yml
index 9ab7af7..564aeaa 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -177,6 +177,7 @@ services:
   cron:
     class: Drupal\Core\Cron
     arguments: ['@module_handler', '@lock', '@queue', '@state', '@account_switcher', '@logger.channel.cron', '@plugin.manager.queue_worker']
+    lazy: true
   diff.formatter:
     class: Drupal\Core\Diff\DiffFormatter
     arguments: ['@config.factory']
@@ -395,6 +396,7 @@ services:
     parent: default_plugin_manager
   plugin.cache_clearer:
     class: Drupal\Core\Plugin\CachedDiscoveryClearer
+    lazy: true
   paramconverter.menu_link:
     class: Drupal\Core\ParamConverter\MenuLinkPluginConverter
     tags:
diff --git a/core/lib/Drupal/Component/ProxyBuilder/ProxyBuilder.php b/core/lib/Drupal/Component/ProxyBuilder/ProxyBuilder.php
new file mode 100644
index 0000000..bce65dc
--- /dev/null
+++ b/core/lib/Drupal/Component/ProxyBuilder/ProxyBuilder.php
@@ -0,0 +1,252 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\ProxyBuilder\ProxyBuilder.
+ */
+
+namespace Drupal\Component\ProxyBuilder;
+
+/**
+ * Generates the string representation of the proxy service.
+ */
+class ProxyBuilder {
+
+  /**
+   * Generates the used proxy class name from a given class name.
+   *
+   * @param string $class_name
+   *   The class name of the actual service.
+   *
+   * @return string
+   *   The class name of the proxy.
+   */
+  public static function buildProxyClassName($class_name) {
+    return str_replace('\\', '_', $class_name) . '_Proxy';
+  }
+
+  /**
+   * Builds a proxy class string.
+   *
+   * @param string $class_name
+   *   The class name of the actual service.
+   *
+   * @return string
+   *   The full string with namespace class and methods.
+   */
+  public function build($class_name) {
+    $reflection = new \ReflectionClass($class_name);
+
+    $output = '';
+    $class_documentation = <<<'EOS'
+/**
+ * Provides a proxy class for \{{ class_name }}.
+ *
+ * @see \Drupal\Component\ProxyBuilder
+ */
+
+EOS;
+    $class_start = 'class {{ proxy_class_name }}';
+
+    if ($interfaces = $reflection->getInterfaceNames()) {
+      foreach ($interfaces as &$interface) {
+        $interface = '\\' . $interface;
+      }
+      $class_start .= ' implements ' . implode(', ', $interfaces);
+    }
+
+    // The actual class;
+    $properties = <<<'EOS'
+/**
+ * @var string
+ */
+protected $serviceId;
+
+/**
+ * @var \{{ class_name }}
+ */
+protected $service;
+
+
+EOS;
+
+    $output .= $properties;
+
+    // Add all the methods.
+    $methods = [];
+    $methods[] = $this->buildConstructorMethod();
+    $methods[] = $this->buildLazyLoadItselfMethod();
+
+    // Add all the methods of the proxied service.
+    $reflection_methods = $reflection->getMethods();
+
+    foreach ($reflection_methods as $method) {
+      if ($method->getName() === '__construct') {
+        continue;
+      }
+
+      if ($method->isPublic()) {
+        $methods[] = $this->buildMethod($method) . "\n";
+      }
+    }
+
+    $output .= implode("\n", $methods);
+
+    // Indent the output.
+    $output = implode("\n", array_map(function($value) {
+      if ($value === '') {
+        return $value;
+      }
+      return "  $value";
+    }, explode("\n", $output)));
+
+    $final_output = $class_documentation . $class_start . "\n{\n\n" . $output . "\n}\n";
+
+    $final_output = str_replace('{{ class_name }}', $class_name, $final_output);
+    $final_output = str_replace('{{ proxy_class_name }}', $this->buildProxyClassName($class_name), $final_output);
+
+    return $final_output;
+  }
+
+  /**
+   * Generates the string for the method which loads the actual service.
+   *
+   * @return string
+   */
+  protected function buildLazyLoadItselfMethod() {
+    $output = <<<'EOS'
+protected function lazyLoadItself()
+{
+    if (!isset($this->service)) {
+        $method_name = 'get' . Container::camelize($this->serviceId) . 'Service';
+        $this->service = $this->container->$method_name(false);
+    }
+
+    return $this->service;
+}
+
+EOS;
+
+    return $output;
+  }
+
+  /**
+   * Generates the string representation of a single method: signature, body.
+   *
+   * @param \ReflectionMethod $reflection_method
+   *   A reflection method for the method.
+   *
+   * @return string
+   */
+  protected function buildMethod(\ReflectionMethod $reflection_method) {
+
+    $parameters = [];
+    foreach ($reflection_method->getParameters() as $parameter) {
+      $parameters[] = $this->buildParameter($parameter);
+    }
+
+    $function_name = $reflection_method->getName();
+
+    if ($reflection_method->isStatic()) {
+      $signature_line = 'public static function ' . $function_name . '(';
+    }
+    else {
+      $signature_line = 'public function ' . $function_name . '(';
+    }
+
+    $signature_line .= implode(', ', $parameters);
+    $signature_line .= ')';
+
+    $output = $signature_line . "\n{\n";
+
+    $output .= $this->buildMethodBody($reflection_method);
+
+    $output .= "\n". '}';
+    return $output;
+  }
+
+  /**
+   * Builds a string for a single parameter of a method.
+   *
+   * @param \ReflectionParameter $parameter
+   *   A reflection object of the parameter.
+   *
+   * @return string
+   */
+  protected function buildParameter(\ReflectionParameter $parameter) {
+    $parameter_string = '';
+
+    if ($parameter->isArray()) {
+      $parameter_string .= 'array ';
+    }
+    elseif ($parameter->isCallable()) {
+      $parameter_string .= 'callable ';
+    }
+    elseif ($class = $parameter->getClass()) {
+      $parameter_string .= '\\' . $class->getName() . ' ';
+    }
+
+    if ($parameter->isPassedByReference()) {
+      $parameter_string .= '&';
+    }
+
+    $parameter_string .= '$' . $parameter->getName();
+
+    if ($parameter->isDefaultValueAvailable()) {
+      $parameter_string .= ' = ';
+      $parameter_string .= var_export($parameter->getDefaultValue(), TRUE);
+    }
+
+    return $parameter_string;
+  }
+
+  /**
+   * Builds the body of a wrapped method.
+   *
+   * @param \ReflectionMethod $reflection_method
+   *   A reflection method for the method.
+   *
+   * @return string
+   */
+  protected function buildMethodBody(\ReflectionMethod $reflection_method) {
+    $output = '';
+
+    $function_name = $reflection_method->getName();
+
+    if (!$reflection_method->isStatic()) {
+      $output .= '    return $this->lazyLoadItself()->' . $function_name . '(';
+    }
+    else {
+      $class_name = $reflection_method->getDeclaringClass()->getName();
+      $output .= "    \\$class_name::$function_name(";
+    }
+
+    // Add parameters;
+    $parameters = [];
+    foreach ($reflection_method->getParameters() as $parameter) {
+      $parameters[] = '$' . $parameter->getName();
+    }
+
+    $output .= implode(', ', $parameters) . ');';
+
+    return $output;
+  }
+
+  /**
+   * Builds the constructor used to inject the actual service ID.
+   *
+   * @return string
+   */
+  protected function buildConstructorMethod() {
+    $output = <<<'EOS'
+public function __construct(ContainerInterface $container, $serviceId)
+{
+    $this->container = $container;
+    $this->serviceId = $serviceId;
+}
+
+EOS;
+
+    return $output;
+  }
+}
diff --git a/core/lib/Drupal/Component/ProxyBuilder/ProxyDumper.php b/core/lib/Drupal/Component/ProxyBuilder/ProxyDumper.php
new file mode 100644
index 0000000..99eae59
--- /dev/null
+++ b/core/lib/Drupal/Component/ProxyBuilder/ProxyDumper.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\ProxyBuilder\ProxyDumper.
+ */
+
+namespace Drupal\Component\ProxyBuilder;
+
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;
+
+/**
+ * Dumps the proxy service into the dumped PHP container file.
+ */
+class ProxyDumper implements DumperInterface {
+
+  /**
+   * The proxy builder.
+   *
+   * @var \Drupal\Component\ProxyBuilder\ProxyBuilder
+   */
+  protected $builder;
+
+  public function __construct(ProxyBuilder $builder) {
+    $this->builder = $builder;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isProxyCandidate(Definition $definition) {
+    return $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getProxyFactoryCode(Definition $definition, $id) {
+    // Note: the specific get method is called initially with $lazyLoad=TRUE;
+    // When you want to retrieve the actual service, the code generated in
+    // ProxyBuilder calls the method with lazy loading disabled.
+    $output = <<<'EOS'
+        if ($lazyLoad) {
+            return $this->services['{{ id }}'] = new {{ class_name }}($this, '{{ id }}');
+        }
+
+EOS;
+    $output = str_replace('{{ id }}', $id, $output);
+    $output = str_replace('{{ class_name }}', $this->builder->buildProxyClassName($definition->getClass()), $output);
+
+    return $output;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getProxyCode(Definition $definition) {
+    return $this->builder->build($definition->getClass());
+  }
+
+}
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index d5e6059..8a993d6 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core;
 
+use Drupal\Component\ProxyBuilder\ProxyBuilder;
+use Drupal\Component\ProxyBuilder\ProxyDumper;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Timer;
 use Drupal\Component\Utility\Unicode;
@@ -1151,6 +1153,7 @@ protected function dumpDrupalContainer(ContainerBuilder $container, $baseClass)
     }
     // Cache the container.
     $dumper = new PhpDumper($container);
+    $dumper->setProxyDumper(new ProxyDumper(new ProxyBuilder()));
     $class = $this->getClassName();
     $content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass));
     return $this->storage()->save($class . '.php', $content);
diff --git a/core/tests/Drupal/Tests/Component/ProxyBuilder/ProxyBuilderTest.php b/core/tests/Drupal/Tests/Component/ProxyBuilder/ProxyBuilderTest.php
new file mode 100644
index 0000000..13c2478
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/ProxyBuilder/ProxyBuilderTest.php
@@ -0,0 +1,313 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\ProxyBuilder\ProxyBuilderTest.
+ */
+
+namespace Drupal\Tests\Component\ProxyBuilder;
+
+use Drupal\Component\ProxyBuilder\ProxyBuilder;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Component\ProxyBuilder\ProxyBuilder
+ * @group proxy_builder
+ */
+class ProxyBuilderTest extends UnitTestCase {
+
+  /**
+   * The tested proxy builder.
+   *
+   * @var \Drupal\Component\ProxyBuilder\ProxyBuilder
+   */
+  protected $proxyBuilder;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->proxyBuilder = new ProxyBuilder();
+  }
+
+  /**
+   * @covers ::buildProxyClassName()
+   */
+  public function testBuildProxyClassName() {
+    $class_name = $this->proxyBuilder->buildProxyClassName('Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod');
+    $this->assertEquals('Drupal_Tests_Component_ProxyBuilder_TestServiceNoMethod_Proxy', $class_name);
+  }
+
+  /**
+   * Tests the basic methods like the constructor and the lazyLoadItself method.
+   *
+   * @covers ::build()
+   * @covers ::buildConstructorMethod()
+   * @covers ::buildLazyLoadItselfMethod()
+   */
+  public function testBuildNoMethod() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod';
+
+    $result = $this->proxyBuilder->build($class);
+    $this->assertEquals($this->buildExpectedClass($class, ''), $result);
+  }
+
+  /**
+   * @covers ::buildMethod()
+   * @covers ::buildMethodBody()
+   */
+  public function testBuildSimpleMethod() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceSimpleMethod';
+
+    $result = $this->proxyBuilder->build($class);
+
+    $method_body = <<<'EOS'
+
+  public function method()
+  {
+      return $this->lazyLoadItself()->method();
+  }
+
+EOS;
+    $this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
+  }
+
+  /**
+   * @covers ::buildMethod()
+   * @covers ::buildParameter()
+   * @covers ::buildMethodBody()
+   */
+  public function testBuildMethodWithParameter() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceMethodWithParameter';
+
+    $result = $this->proxyBuilder->build($class);
+
+    $method_body = <<<'EOS'
+
+  public function methodWithParameter($parameter)
+  {
+      return $this->lazyLoadItself()->methodWithParameter($parameter);
+  }
+
+EOS;
+    $this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
+  }
+
+  /**
+   * @covers ::buildMethod()
+   * @covers ::buildParameter()
+   * @covers ::buildMethodBody()
+   */
+  public function testBuildComplexMethod() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceComplexMethod';
+
+    $result = $this->proxyBuilder->build($class);
+
+    // @todo Solve the silly linebreak for array()
+    $method_body = <<<'EOS'
+
+  public function complexMethod($parameter, callable $function, \Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod $test_service = NULL, array &$elements = array (
+  ))
+  {
+      return $this->lazyLoadItself()->complexMethod($parameter, $function, $test_service, $elements);
+  }
+
+EOS;
+
+    $this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
+  }
+
+  /**
+   * @covers ::buildMethod()
+   * @covers ::buildParameter()
+   * @covers ::buildMethodBody()
+   */
+  public function testBuildWithInterface() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceWithInterface';
+
+    $result = $this->proxyBuilder->build($class);
+
+    $method_body = <<<'EOS'
+
+  public function testMethod($parameter)
+  {
+      return $this->lazyLoadItself()->testMethod($parameter);
+  }
+
+EOS;
+
+    $interface_string = ' implements \Drupal\Tests\Component\ProxyBuilder\TestInterface';
+    $this->assertEquals($this->buildExpectedClass($class, $method_body, $interface_string), $result);
+  }
+
+  /**
+   * @covers ::buildMethod()
+   * @covers ::buildParameter()
+   * @covers ::buildMethodBody()
+   */
+  public function testBuildWithProtectedAndPrivateMethod() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceWithProtectedMethods';
+
+    $result = $this->proxyBuilder->build($class);
+
+    $method_body = <<<'EOS'
+
+  public function testMethod($parameter)
+  {
+      return $this->lazyLoadItself()->testMethod($parameter);
+  }
+
+EOS;
+
+$this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
+  }
+
+  /**
+   * @covers ::buildMethod()
+   * @covers ::buildParameter()
+   * @covers ::buildMethodBody()
+   */
+  public function testBuildWithPublicStaticMethod() {
+    $class = 'Drupal\Tests\Component\ProxyBuilder\TestServiceWithPublicStaticMethod';
+
+    $result = $this->proxyBuilder->build($class);
+
+    // Ensure that the static method is not wrapped.
+    $method_body = <<<'EOS'
+
+  public static function testMethod($parameter)
+  {
+      \Drupal\Tests\Component\ProxyBuilder\TestServiceWithPublicStaticMethod::testMethod($parameter);
+  }
+
+EOS;
+
+    $this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
+  }
+
+  /**
+   * Constructs the expected class output.
+   *
+   * @param string $expected_methods_body
+   *   The expected body of decorated methods.
+   *
+   * @return string
+   *   The code of the entire proxy.
+   */
+  protected function buildExpectedClass($class, $expected_methods_body, $interface_string = '') {
+    $proxy_class = $this->proxyBuilder->buildProxyClassName($class);
+    $expected_string = <<<'EOS'
+/**
+ * Provides a proxy class for \{{ class }}.
+ *
+ * @see \Drupal\Component\ProxyBuilder
+ */
+class {{ proxy_class }}{{ interface_string }}
+{
+
+  /**
+   * @var string
+   */
+  protected $serviceId;
+
+  /**
+   * @var \{{ class }}
+   */
+  protected $service;
+
+  public function __construct(ContainerInterface $container, $serviceId)
+  {
+      $this->container = $container;
+      $this->serviceId = $serviceId;
+  }
+
+  protected function lazyLoadItself()
+  {
+      if (!isset($this->service)) {
+          $method_name = 'get' . Container::camelize($this->serviceId) . 'Service';
+          $this->service = $this->container->$method_name(false);
+      }
+
+      return $this->service;
+  }
+{{ expected_methods_body }}
+}
+
+EOS;
+    $expected_string = str_replace('{{ proxy_class }}', $proxy_class, $expected_string);
+    $expected_string = str_replace('{{ class }}', $class, $expected_string);
+    $expected_string = str_replace('{{ expected_methods_body }}', $expected_methods_body, $expected_string);
+    $expected_string = str_replace('{{ interface_string }}', $interface_string, $expected_string);
+
+    return $expected_string;
+  }
+
+}
+
+class TestServiceNoMethod {
+
+}
+
+class TestServiceSimpleMethod {
+
+  public function method() {
+
+  }
+
+}
+
+class TestServiceMethodWithParameter {
+
+  public function methodWithParameter($parameter) {
+
+  }
+
+}
+
+class TestServiceComplexMethod {
+
+  public function complexMethod($parameter, callable $function, TestServiceNoMethod $test_service = NULL, array &$elements = array()) {
+
+  }
+
+}
+
+interface TestInterface {
+
+  public function testMethod($parameter);
+
+}
+
+class TestServiceWithInterface implements TestInterface {
+
+  public function testMethod($parameter) {
+
+  }
+
+}
+
+class TestServiceWithProtectedMethods {
+
+  public function testMethod($parameter) {
+
+  }
+
+  protected function protectedMethod($parameter) {
+
+  }
+
+  protected function privateMethod($parameter) {
+
+  }
+
+}
+
+class TestServiceWithPublicStaticMethod {
+
+  public static function testMethod($parameter) {
+  }
+
+}
+
diff --git a/core/tests/Drupal/Tests/Component/ProxyBuilder/ProxyDumperTest.php b/core/tests/Drupal/Tests/Component/ProxyBuilder/ProxyDumperTest.php
new file mode 100644
index 0000000..d8fed50
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/ProxyBuilder/ProxyDumperTest.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\ProxyBuilder\ProxyDumperTest.
+ */
+
+namespace Drupal\Tests\Component\ProxyBuilder;
+
+use Drupal\Component\ProxyBuilder\ProxyDumper;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\Definition;
+
+/**
+ * @coversDefaultClass \Drupal\Component\ProxyBuilder\ProxyDumper
+ * @group proxy_builder
+ */
+class ProxyDumperTest extends UnitTestCase {
+
+  /**
+   * The mocked proxy builder.
+   *
+   * @var \Drupal\Component\ProxyBuilder\ProxyBuilder|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $proxyBuilder;
+
+  /**
+   * The tested proxy dumper.
+   *
+   * @var \Drupal\Component\ProxyBuilder\ProxyDumper
+   */
+  protected $proxyDumper;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->proxyBuilder = $this->getMockBuilder('Drupal\Component\ProxyBuilder\ProxyBuilder')
+      ->disableOriginalConstructor()
+      ->setMethods(['build'])
+      ->getMock();
+    $this->proxyDumper = new ProxyDumper($this->proxyBuilder);
+  }
+
+  /**
+   * @dataProvider providerTestIsProxyCandidate
+   * @covers ::isProxyCandidate()
+   */
+  public function testIsProxyCandidate(Definition $definition, $expected) {
+    $this->assertSame($expected, $this->proxyDumper->isProxyCandidate($definition));
+  }
+
+  public function providerTestIsProxyCandidate() {
+    // Not lazy service.
+    $data = [];
+    $definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
+    $data[] = [$definition, FALSE];
+    // Not existing service.
+    $definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestNotExistingService');
+    $definition->setLazy(TRUE);
+    $data[] = [$definition, FALSE];
+    // Existing and lazy service.
+    $definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
+    $definition->setLazy(TRUE);
+    $data[] = [$definition, TRUE];
+
+    return $data;
+  }
+
+  public function testGetProxyFactoryCode() {
+    $definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
+    $definition->setLazy(TRUE);
+
+    $result = $this->proxyDumper->getProxyFactoryCode($definition, 'test_service');
+
+    $expected = <<<'EOS'
+        if ($lazyLoad) {
+            return $this->services['test_service'] = new Drupal_Tests_Component_ProxyBuilder_TestService_Proxy($this, 'test_service');
+        }
+
+EOS;
+
+    $this->assertEquals($expected, $result);
+  }
+
+  public function testGetProxyCode() {
+    $definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
+    $definition->setLazy(TRUE);
+
+    $class = 'class Drupal_Tests_Component_ProxyBuilder_TestService_Proxy {}';
+    $this->proxyBuilder->expects($this->once())
+      ->method('build')
+      ->with('Drupal\Tests\Component\ProxyBuilder\TestService')
+      ->willReturn($class);
+
+    $result = $this->proxyDumper->getProxyCode($definition);
+    $this->assertEquals($class, $result);
+  }
+
+}
+
+class TestService {
+
+}
