diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 4250091..3368e72 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -3,7 +3,8 @@
 use Drupal\Core\Database\Database;
 use Symfony\Component\ClassLoader\UniversalClassLoader;
 use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Drupal\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
 
 /**
  * @file
@@ -2152,6 +2153,14 @@ function _drupal_bootstrap_configuration() {
     // All Drupal-namespaced code in core lives in /core/lib/Drupal.
     'Drupal' => DRUPAL_ROOT . '/core/lib',
   ));
+
+  // Register fallback implementations for the cache and plugin systems.
+  drupal_container()->registerFallback('cache.{cache.bin}', 'Drupal\Core\Cache\DatabaseBackend')
+    ->setArguments(array('%cache.bin%'));
+  drupal_container()->registerFallback('plugin.discovery.{plugin.scope}.{plugin.type}', 'Drupal\Core\Plugin\DefinitionDiscovery\DefinitionDiscoveryFromConfig')
+    ->setArguments(array('plugin.type.%plugin.scope%.%plugin.type%', 'plugin.plugin.%plugin.scope%.%plugin.type%'));
+  drupal_container()->registerFallback('plugin.type.{plugin.scope}.{plugin.type}', 'Drupal\Component\Plugin\PluginType')
+    ->setArguments(array('%plugin.scope%', '%plugin.type%', new Reference('plugin.discovery.%plugin.scope%.%plugin.type%')));
 }
 
 /**
@@ -2322,7 +2331,7 @@ function drupal_get_bootstrap_phase() {
  * @param $reset
  *   TRUE or FALSE depending on whether the Container instance is to be reset.
  *
- * @return Symfony\Component\DependencyInjection\ContainerBuilder
+ * @return Drupal\Component\DependencyInjection\ContainerBuilder
  *   The instance of the Drupal Container used to set up and maintain object
  *   instances.
  */
diff --git a/core/includes/cache.inc b/core/includes/cache.inc
index d3c3414..d0b7391 100644
--- a/core/includes/cache.inc
+++ b/core/includes/cache.inc
@@ -28,17 +28,7 @@ function cache($bin = 'cache') {
   // bin names to be passed as arguments.
   $bin = str_replace('cache_', '', $bin);
 
-  // We do not use drupal_static() here because we do not want to change the
-  // storage of a cache bin mid-request.
-  static $cache_objects;
-  if (!isset($cache_objects[$bin])) {
-    $class = variable_get('cache_class_' . $bin);
-    if (!isset($class)) {
-      $class = variable_get('cache_default_class', 'Drupal\Core\Cache\DatabaseBackend');
-    }
-    $cache_objects[$bin] = new $class($bin);
-  }
-  return $cache_objects[$bin];
+  return drupal_container()->get('cache.' . $bin);
 }
 
 /**
diff --git a/core/includes/common.inc b/core/includes/common.inc
index e57ca93..c3acbee 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -5141,6 +5141,7 @@ function _drupal_bootstrap_full() {
   require_once DRUPAL_ROOT . '/core/includes/token.inc';
   require_once DRUPAL_ROOT . '/core/includes/errors.inc';
   require_once DRUPAL_ROOT . '/core/includes/schema.inc';
+  require_once DRUPAL_ROOT . '/core/includes/plugin.inc';
 
   // Detect string handling method
   unicode_check();
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 07e25a0..df421bd 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -297,7 +297,8 @@ function install_begin_request(&$install_state) {
   // because any data put in the cache during the installer is inherently
   // suspect, due to the fact that Drupal is not fully set up yet.
   require_once DRUPAL_ROOT . '/core/includes/cache.inc';
-  $conf['cache_default_class'] = 'Drupal\Core\Cache\InstallBackend';
+  drupal_container()->registerFallback('cache.{cache.bin}', 'Drupal\Core\Cache\InstallBackend')
+    ->setArguments(array('%cache.bin%'));
 
   // Prepare for themed output. We need to run this at the beginning of the
   // page request to avoid a different theme accidentally getting set. (We also
diff --git a/core/includes/plugin.inc b/core/includes/plugin.inc
new file mode 100644
index 0000000..07af269
--- /dev/null
+++ b/core/includes/plugin.inc
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Functions for plugin handling.
+ *
+ * @todo Add documentation explaining the plugin system and how plugin types,
+ *   plugins, and plugin instances fit together.
+ */
+
+/**
+ * @todo Add documentation.
+ */
+function plugin_get_type($scope, $type) {
+  return drupal_container()->get("plugin.type.$scope.$type");
+}
+
+/**
+ * @todo Add documentation.
+ */
+function plugin_get_plugin($scope, $type, $id) {
+  return drupal_container()->get("plugin.type.$scope.$type")->getPlugin($id);
+}
+
+/**
+ * @todo Add documentation.
+ */
+function plugin_get_instance($scope, $type, $id, $configuration) {
+  return drupal_container()->get("plugin.type.$scope.$type")->getPlugin($id)->getInstance($configuration);
+}
diff --git a/core/lib/Drupal/Component/DependencyInjection/ContainerBuilder.php b/core/lib/Drupal/Component/DependencyInjection/ContainerBuilder.php
new file mode 100644
index 0000000..640767c
--- /dev/null
+++ b/core/lib/Drupal/Component/DependencyInjection/ContainerBuilder.php
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\DependencyInjection\ContainerBuilder.
+ */
+
+namespace Drupal\Component\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+
+/**
+ * @todo Add documentation here.
+ */
+class ContainerBuilder extends SymfonyContainerBuilder {
+  protected $fallbacks = array();
+
+  /**
+   * @todo Add documentation here.
+   */
+  public function registerFallback($idPattern, $class = null) {
+    return $this->fallbacks[strtolower($idPattern)] = new Definition($class);
+  }
+
+  /**
+   * @todo Add documentation here.
+   */
+  public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
+    $id = strtolower($id);
+
+    try {
+      return parent::get($id, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
+    }
+    catch (InvalidArgumentException $e) {
+      // If a fallback service definition exists, create a service based on
+      // that, populating the service container with parameters fetched from the
+      // service id.
+      if (!$this->hasDefinition($id) && ($fallback = $this->findFallback($id))) {
+        $parameters = $this->getParametersFromId($id, $fallback);
+        $priorParameters = array();
+        foreach ($parameters as $name => $value) {
+          $priorParameters[$name] = $this->hasParameter($name) ? $this->getParameter($name) : NULL;
+          $this->setParameter($name, $value);
+        }
+        $this->setDefinition($id, $this->fallbacks[$fallback]);
+        $service = $this->get($id, $invalidBehavior);
+        foreach ($priorParameters as $name => $value) {
+          $this->setParameter($name, $value);
+        }
+        return $service;
+      }
+
+      if ($invalidBehavior === ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
+        throw $e;
+      }
+    }
+  }
+
+  /**
+   * Extends Symfony's ContainerBuilder::resolveServices() to resolve parameters in service identifiers.
+   */
+  public function resolveServices($value) {
+    if (is_object($value) && $value instanceof Reference) {
+      return $this->get($this->getParameterBag()->resolveValue((string) $value), $value->getInvalidBehavior());
+    }
+    else {
+      return parent::resolveServices($value);
+    }
+  }
+
+  /**
+   * @todo Add documentation here.
+   */
+  protected function findFallback($id) {
+    // @todo Optimize this by structuring $this->fallbacks to be more
+    //   efficiently searched.
+    // @todo Add best fit logic if there are multiple matches. For example, if
+    //   $id = 'a.b.c' and there are two fallbacks: 'a.{foo}.{bar}' and
+    //   'a.b.{bar}', the latter (more specific) one should be returned.
+    foreach ($this->fallbacks as $fallback => $definition) {
+      $regex = '/' . preg_replace('/\\\{.*?\\\}/', '\\w+', preg_quote($fallback, '/')) . '/';
+      if (preg_match($regex, $id)) {
+        return $fallback;
+      }
+    }
+  }
+
+  /**
+   * @todo Add documentation here.
+   */
+  protected function getParametersFromId($id, $fallback) {
+    // @todo Clean this up. Basically, if $fallback = 'a.b.{c.d}.{e.f}.g' and
+    //   $id = 'a.b.foo.bar.g', return array('c.d' => 'foo', 'e.f' => 'bar').
+    $idParts = explode('.', $id);
+    $parameters = array();
+    $fallbackParts = array();
+    $fallbackPart = array();
+    $placeholder = FALSE;
+    foreach (explode('.', $fallback) as $part) {
+      if (substr($part, 0, 1) == '{') {
+        $fallbackPart = array();
+        $placeholder = TRUE;
+      }
+      if (substr($part, -1, 1) == '}') {
+        $placeholder = FALSE;
+        $fallbackPart[] = $part;
+        $part = implode('.', $fallbackPart);
+      }
+      if ($placeholder) {
+        $fallbackPart[] = $part;
+      }
+      else {
+        $fallbackParts[] = $part;
+      }
+    }
+    foreach ($fallbackParts as $i => $part) {
+      if (substr($part, 0, 1) == '{' && substr($part, -1, 1) == '}') {
+        $parameters[substr($part, 1, -1)] = $idParts[$i];
+      }
+    }
+    return $parameters;
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/DefinitionDiscovery/DefinitionDiscoveryFromCaller.php b/core/lib/Drupal/Component/Plugin/DefinitionDiscovery/DefinitionDiscoveryFromCaller.php
new file mode 100644
index 0000000..526ff6f
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/DefinitionDiscovery/DefinitionDiscoveryFromCaller.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\DefinitionDiscovery\DefinitionDiscoveryFromCaller.
+ */
+
+namespace Drupal\Component\Plugin\DefinitionDiscovery;
+
+/**
+ * Implements a class for returning plugin type and plugin definitions provided by the caller instantiating this class.
+ */
+class DefinitionDiscoveryFromCaller implements DefinitionDiscoveryInterface {
+
+  protected $pluginTypeDefinition;
+  protected $pluginDefinitions;
+
+  public function __construct($pluginTypeDefinition = array(), $pluginDefinitions = array()) {
+    $this->pluginTypeDefinition = $pluginTypeDefinition;
+    $this->pluginDefinitions = $pluginDefinitions;
+  }
+
+  public function getPluginTypeDefinition() {
+    return $this->pluginTypeDefinition;
+  }
+
+  public function getPluginIds() {
+    return array_keys($this->pluginDefinitions);
+  }
+
+  public function getPluginDefinition($id) {
+    return $this->pluginDefinitions[$id];
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/DefinitionDiscovery/DefinitionDiscoveryInterface.php b/core/lib/Drupal/Component/Plugin/DefinitionDiscovery/DefinitionDiscoveryInterface.php
new file mode 100644
index 0000000..f9cf657
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/DefinitionDiscovery/DefinitionDiscoveryInterface.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\DefinitionDiscovery\DefinitionDiscoveryInterface.
+ */
+
+namespace Drupal\Component\Plugin\DefinitionDiscovery;
+
+/**
+ * Defines an interface for getting the definition of a plugin type and its available plugins.
+ */
+interface DefinitionDiscoveryInterface {
+
+  /**
+   * Get the plugin type definition.
+   *
+   * @return array
+   *   The plugin type definition.
+   */
+  public function getPluginTypeDefinition();
+
+  /**
+   * Get the list of all plugins for a type.
+   *
+   * @return array
+   *   An array of plugin ids.
+   */
+  public function getPluginIds();
+
+  /**
+   * Get the definition of a particular plugin.
+   *
+   * @param string $id
+   *   A plugin id.
+   *
+   * @return array
+   *   The plugin definition.
+   */
+  public function getPluginDefinition($id);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Exception/PluginException.php b/core/lib/Drupal/Component/Plugin/Exception/PluginException.php
new file mode 100644
index 0000000..731b4c5
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Exception/PluginException.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * @file
+ * Base exception object for grouping other plugin exceptions.
+ */
+
+namespace Drupal\Component\Plugin\Exception;
+
+/**
+ * Exception class used as a base for plugin related errors.
+ */
+class PluginException extends \Exception { }
diff --git a/core/lib/Drupal/Component/Plugin/Plugin.php b/core/lib/Drupal/Component/Plugin/Plugin.php
new file mode 100644
index 0000000..fc2db36
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Plugin.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\Plugin.
+ */
+
+namespace Drupal\Component\Plugin;
+use Drupal\Component\Plugin\DefinitionDiscovery\DefinitionDiscoveryInterface;
+
+/**
+ * @todo Add documentation.
+ */
+class Plugin implements PluginInterface {
+
+  protected $pluginType;
+  protected $id;
+  protected $definition;
+
+  public function __construct(PluginTypeInterface $pluginType, $id, DefinitionDiscoveryInterface $definitionDiscoverer) {
+    $this->pluginType = $pluginType;
+    $this->id = $id;
+    $this->definition = $definitionDiscoverer->getPluginDefinition($id);
+  }
+
+  public function getDefinition() {
+    return $this->definition;
+  }
+
+  public function getInstance($configuration) {
+    $factory = $this->getFactory();
+    return call_user_func($factory, $this, $configuration);
+  }
+
+  /**
+   * Helper function that gets the PHP callable to use for creating a plugin instance.
+   */
+  protected function getFactory() {
+    return isset($this->definition['plugin']['instance_creation']['factory']) ? $this->definition['plugin']['instance_creation']['factory'] : 'Drupal\Component\Plugin\PluginInstanceFactory::createInstance';
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginInstanceFactory.php b/core/lib/Drupal/Component/Plugin/PluginInstanceFactory.php
new file mode 100644
index 0000000..cdef0e8
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginInstanceFactory.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\PluginInstanceFactory.
+ */
+
+namespace Drupal\Component\Plugin;
+use Drupal\Component\Plugin\Exception\PluginException;
+
+/**
+ * @todo Add documentation.
+ */
+class PluginInstanceFactory {
+
+  /**
+   * @todo This function is static to make it easy to use as a callable from
+   *   serialized configuration. At some point, it may be desirable to make
+   *   Drupal\Component\Plugin\Plugin::getFactory() support object callables.
+   */
+  public static function createInstance(PluginInterface $plugin, array $configuration) {
+    // Get the class to instantiate.
+    $class = self::getInstanceClass($plugin);
+    if (empty($class)) {
+      throw new PluginException('Plugin instance class was not specified.');
+    }
+    if (!class_exists($class)) {
+      throw new PluginException(sprintf('Plugin instance class "%s" does not exist.', $class));
+    }
+
+    // Create the instance. If the constructor takes arguments, populate them
+    // with the corresponding configuration value.
+    $reflector = new \ReflectionClass($class);
+    if ($reflector->hasMethod('__construct')) {
+      $parameters = $reflector->getMethod('__construct')->getParameters();
+      $arguments = array();
+      foreach ($parameters as $parameter) {
+        $arguments[] = isset($configuration[$parameter->name]) ? $configuration[$parameter->name] : NULL;
+      }
+      $instance = $reflector->newInstanceArgs($arguments);
+    }
+    else {
+      $instance = new $class();
+    }
+
+    // Plugins that require more configuration beyond constructor arguments can
+    // define a PHP callable to invoke.
+    if ($configurator = self::getInstanceConfigurator($plugin)) {
+      call_user_func($configurator, $instance, $configuration);
+    }
+
+    return $instance;
+  }
+
+  /**
+   * Helper function that gets the class to instantiate.
+   */
+  protected static function getInstanceClass(PluginInterface $plugin) {
+    $definition = $plugin->getDefinition();
+    return isset($definition['plugin']['instance_creation']['class']) ? $definition['plugin']['instance_creation']['class'] : NULL;
+  }
+
+  /**
+   * Helper function that gets the PHP callable to use for configuring a plugin instance.
+   */
+  protected static function getInstanceConfigurator(PluginInterface $plugin) {
+    $definition = $plugin->getDefinition();
+    return isset($definition['plugin']['instance_creation']['configurator']) ? $definition['plugin']['instance_creation']['configurator'] : NULL;
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginInterface.php b/core/lib/Drupal/Component/Plugin/PluginInterface.php
new file mode 100644
index 0000000..62f2c5b
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\PluginInterface.
+ */
+
+namespace Drupal\Component\Plugin;
+
+/**
+ * Defines an interface for accessing information about a plugin and creating configured instances for it.
+ */
+interface PluginInterface {
+
+  /**
+   * Get the plugin definition.
+   *
+   * @return array
+   *   The plugin definition.
+   */
+  public function getDefinition();
+
+  /**
+   * Get a configured instance of this plugin.
+   *
+   * @param array $configuration
+   *   Configuration data for the instance.
+   *
+   * @return object
+   *   A plugin instance. The plugin implementation determines what class to
+   *   instantiate for its plugin instances.
+   */
+  public function getInstance($configuration);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginType.php b/core/lib/Drupal/Component/Plugin/PluginType.php
new file mode 100644
index 0000000..bd87e35
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginType.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\PluginType.
+ */
+
+namespace Drupal\Component\Plugin;
+use Drupal\Component\Plugin\DefinitionDiscovery\DefinitionDiscoveryInterface;
+use Drupal\Component\Plugin\Exception\PluginException;
+
+/**
+ * @todo Add documentation.
+ */
+class PluginType implements PluginTypeInterface {
+
+  protected $scope;
+  protected $type;
+  protected $definition;
+  protected $definitionDiscoverer;
+  protected $plugins = array();
+
+  public function __construct($scope, $type, $definitionDiscoverer) {
+    $this->scope = $scope;
+    $this->type = $type;
+    $this->definition = $definitionDiscoverer->getPluginTypeDefinition();
+    $this->definitionDiscoverer = $definitionDiscoverer;
+  }
+
+  public function getDefinition() {
+    return $this->definition;
+  }
+
+  public function getPluginIds() {
+    return $this->definitionDiscoverer->getPluginIds();
+  }
+
+  public function getPlugin($id) {
+    if (!isset($this->plugins[$id])) {
+      $pluginDefinition = $this->definitionDiscoverer->getPluginDefinition($id);
+      if (!isset($pluginDefinition)) {
+        throw new PluginException(sprintf('Plugin "%s" does not exist.', $id));
+      }
+      $class = $this->getPluginClass();
+      if (!class_exists($class)) {
+        throw new PluginException(sprintf('Plugin class "%s" does not exist.', $class));
+      }
+      $this->plugins[$id] = new $class($this, $id, $this->definitionDiscoverer);
+    }
+    return $this->plugins[$id];
+  }
+
+  /**
+   * Helper function that gets the class to use for accessing plugins of this type.
+   */
+  protected function getPluginClass() {
+    return isset($this->definition['plugin']['plugin_class']) ? $this->definition['plugin']['plugin_class'] : 'Drupal\Component\Plugin\Plugin';
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginTypeInterface.php b/core/lib/Drupal/Component/Plugin/PluginTypeInterface.php
new file mode 100644
index 0000000..9d67a8a
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/PluginTypeInterface.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\PluginTypeInterface.
+ */
+
+namespace Drupal\Component\Plugin;
+
+/**
+ * Defines an interface for accessing information about a plugin type and its available plugins.
+ */
+interface PluginTypeInterface {
+
+  /**
+   * Get the plugin type definition.
+   *
+   * @return array
+   *   The plugin type definition.
+   */
+  public function getDefinition();
+
+  /**
+   * Get the list of all plugins for a type.
+   *
+   * @return array
+   *   An array of plugin ids.
+   */
+  public function getPluginIds();
+
+  /**
+   * Get the plugin object for a particular plugin.
+   *
+   * @param string $id
+   *   A plugin id.
+   *
+   * @return Drupal\Component\Plugin\PluginInterface
+   *   The plugin object.
+   */
+  public function getPlugin($id);
+
+}
diff --git a/core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php b/core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php
index 97d499a..12a8852 100644
--- a/core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php
+++ b/core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php
@@ -48,6 +48,6 @@ class DrupalVerifiedStorageSQL extends DrupalConfigVerifiedStorage {
    * Implements DrupalConfigVerifiedStorageInterface::getNamesWithPrefix().
    */
   static public function getNamesWithPrefix($prefix = '') {
-    return db_query('SELECT name FROM {config} WHERE name LIKE :name', array(':name' => db_like($prefix) . '%'))->fetchCol();
+    return db_query('SELECT name FROM {config} WHERE name LIKE :name ORDER BY name', array(':name' => db_like($prefix) . '%'))->fetchCol();
   }
 }
diff --git a/core/lib/Drupal/Core/Plugin/DefinitionDiscovery/DefinitionDiscoveryFromConfig.php b/core/lib/Drupal/Core/Plugin/DefinitionDiscovery/DefinitionDiscoveryFromConfig.php
new file mode 100644
index 0000000..11df57a
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/DefinitionDiscovery/DefinitionDiscoveryFromConfig.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Plugin\DefinitionDiscovery\DefinitionDiscoveryFromConfig.
+ */
+
+namespace Drupal\Core\Plugin\DefinitionDiscovery;
+use Drupal\Component\Plugin\DefinitionDiscovery\DefinitionDiscoveryInterface;
+
+/**
+ * Implements a class for returning plugin type and plugin definitions discovered from Drupal's Config system.
+ */
+class DefinitionDiscoveryFromConfig implements DefinitionDiscoveryInterface {
+
+  protected $pluginTypeDefinition;
+  protected $pluginDefinitions = array();
+  protected $pluginConfigPrefixDefault;
+
+  public function __construct($pluginTypeConfigName, $pluginConfigPrefixDefault) {
+    $this->pluginTypeDefinition = config($pluginTypeConfigName)->get();
+    $this->pluginConfigPrefixDefault = $pluginConfigPrefixDefault;
+  }
+
+  public function getPluginTypeDefinition() {
+    return $this->pluginTypeDefinition;
+  }
+
+  public function getPluginIds() {
+    $pluginIds = array();
+    $configPrefix = $this->getPluginConfigPrefix();
+    $configPrefixLength = strlen($configPrefix);
+    foreach (config_get_verified_storage_names_with_prefix($configPrefix) as $configName) {
+      $pluginIds[] = substr($configName, $configPrefixLength + 1);
+    }
+    return $pluginIds;
+  }
+
+  public function getPluginDefinition($id) {
+    if (!isset($this->pluginDefinitions[$id])) {
+      $this->pluginDefinitions[$id] = config($this->getPluginConfigPrefix() . '.' . $id)->get();
+    }
+    return $this->pluginDefinitions[$id];
+  }
+
+  /**
+   * Helper function that gets the config prefix for plugins of this type.
+   */
+  protected function getPluginConfigPrefix() {
+    return !empty($this->definition['plugin']['config_prefix']) ? $this->definition['plugin']['config_prefix'] : $this->pluginConfigPrefixDefault;
+  }
+}
diff --git a/core/modules/image/config/plugin.plugin.image.effect.image_crop.xml b/core/modules/image/config/plugin.plugin.image.effect.image_crop.xml
new file mode 100644
index 0000000..fe1172d
--- /dev/null
+++ b/core/modules/image/config/plugin.plugin.image.effect.image_crop.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<config>
+  <plugin>
+    <instance_creation>
+      <class>Drupal\image\Effect\CropEffect</class>
+    </instance_creation>
+  </plugin>
+  <label>Crop</label> <!-- TODO: how to handle translation? -->
+  <help>Cropping will remove portions of an image to make it the specified dimensions.</help> <!-- TODO: how to handle translation? -->
+</config>
diff --git a/core/modules/image/config/plugin.plugin.image.effect.image_desaturate.xml b/core/modules/image/config/plugin.plugin.image.effect.image_desaturate.xml
new file mode 100644
index 0000000..67b68d5
--- /dev/null
+++ b/core/modules/image/config/plugin.plugin.image.effect.image_desaturate.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<config>
+  <plugin>
+    <instance_creation>
+      <class>Drupal\image\Effect\DesaturateEffect</class>
+    </instance_creation>
+  </plugin>
+  <label>Desaturate</label> <!-- TODO: how to handle translation? -->
+  <help>Desaturate converts an image to grayscale.</help> <!-- TODO: how to handle translation? -->
+</config>
diff --git a/core/modules/image/config/plugin.plugin.image.effect.image_resize.xml b/core/modules/image/config/plugin.plugin.image.effect.image_resize.xml
new file mode 100644
index 0000000..98ddffb
--- /dev/null
+++ b/core/modules/image/config/plugin.plugin.image.effect.image_resize.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<config>
+  <plugin>
+    <instance_creation>
+      <class>Drupal\image\Effect\ResizeEffect</class>
+    </instance_creation>
+  </plugin>
+  <label>Resize</label> <!-- TODO: how to handle translation? -->
+  <help>Resizing will make images an exact set of dimensions. This may cause images to be stretched or shrunk disproportionately.</help> <!-- TODO: how to handle translation? -->
+</config>
diff --git a/core/modules/image/config/plugin.plugin.image.effect.image_rotate.xml b/core/modules/image/config/plugin.plugin.image.effect.image_rotate.xml
new file mode 100644
index 0000000..e8cb08b
--- /dev/null
+++ b/core/modules/image/config/plugin.plugin.image.effect.image_rotate.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<config>
+  <plugin>
+    <instance_creation>
+      <class>Drupal\image\Effect\RotateEffect</class>
+    </instance_creation>
+  </plugin>
+  <label>Rotate</label> <!-- TODO: how to handle translation? -->
+  <help>Rotating an image may cause the dimensions of an image to increase to fit the diagonal.</help> <!-- TODO: how to handle translation? -->
+</config>
diff --git a/core/modules/image/config/plugin.plugin.image.effect.image_scale.xml b/core/modules/image/config/plugin.plugin.image.effect.image_scale.xml
new file mode 100644
index 0000000..b4d75a1
--- /dev/null
+++ b/core/modules/image/config/plugin.plugin.image.effect.image_scale.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<config>
+  <plugin>
+    <instance_creation>
+      <class>Drupal\image\Effect\ScaleEffect</class>
+    </instance_creation>
+  </plugin>
+  <label>Scale</label> <!-- TODO: how to handle translation? -->
+  <help>Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.</help> <!-- TODO: how to handle translation? -->
+</config>
diff --git a/core/modules/image/config/plugin.plugin.image.effect.image_scale_and_crop.xml b/core/modules/image/config/plugin.plugin.image.effect.image_scale_and_crop.xml
new file mode 100644
index 0000000..10b1b41
--- /dev/null
+++ b/core/modules/image/config/plugin.plugin.image.effect.image_scale_and_crop.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<config>
+  <plugin>
+    <instance_creation>
+      <class>Drupal\image\Effect\ScaleAndCropEffect</class>
+    </instance_creation>
+  </plugin>
+  <label>Scale and crop</label> <!-- TODO: how to handle translation? -->
+  <help>Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.</help> <!-- TODO: how to handle translation? -->
+</config>
diff --git a/core/modules/image/config/plugin.type.image.effect.xml b/core/modules/image/config/plugin.type.image.effect.xml
new file mode 100644
index 0000000..3b5acad
--- /dev/null
+++ b/core/modules/image/config/plugin.type.image.effect.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<config>
+  <!-- TODO: is anything needed here? -->
+</config>
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index ecb72d8..6f1e818 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -1,5 +1,7 @@
 <?php
 
+use Drupal\image\Effect\ImageConfigurableEffectInterface;
+
 /**
  * @file
  * Administration pages for image settings.
@@ -65,13 +67,13 @@ function image_style_form($form, &$form_state, $style) {
   );
   if (!empty($style['effects'])) {
     foreach ($style['effects'] as $key => $effect) {
+      $effect_instance = plugin_get_instance('image', 'effect', $effect['name'], $effect);
+
       $form['effects'][$key]['#weight'] = isset($form_state['input']['effects']) ? $form_state['input']['effects'][$key]['weight'] : NULL;
       $form['effects'][$key]['label'] = array(
         '#markup' => $effect['label'],
       );
-      $form['effects'][$key]['summary'] = array(
-        '#markup' => isset($effect['summary theme']) ? theme($effect['summary theme'], array('data' => $effect['data'])) : '',
-      );
+      $form['effects'][$key]['summary'] = ($effect_instance instanceof ImageConfigurableEffectInterface) ? $effect_instance->viewSummary() : array();
       $form['effects'][$key]['weight'] = array(
         '#type' => 'weight',
         '#title' => t('Weight for @title', array('@title' => $effect['label'])),
@@ -83,7 +85,7 @@ function image_style_form($form, &$form_state, $style) {
         '#type' => 'link',
         '#title' => t('edit'),
         '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $key,
-        '#access' => isset($effect['form callback']),
+        '#access' => $effect_instance instanceof ImageConfigurableEffectInterface,
       );
       $form['effects'][$key]['remove'] = array(
         '#type' => 'link',
@@ -95,7 +97,7 @@ function image_style_form($form, &$form_state, $style) {
 
   // Build the new image effect addition form and add it to the effect list.
   $new_effect_options = array();
-  foreach (image_effect_definitions() as $effect => $definition) {
+  foreach (_image_effect_definitions() as $effect => $definition) {
     $new_effect_options[$effect] = check_plain($definition['label']);
   }
   $form['effects']['new'] = array(
@@ -147,10 +149,10 @@ function image_style_form_add_validate($form, &$form_state) {
 function image_style_form_add_submit($form, &$form_state) {
   $style = $form_state['image_style'];
   // Check if this field has any configuration options.
-  $effect = image_effect_definition_load($form_state['values']['new']);
+  $effect = _image_effect_definition_load($form_state['values']['new']);
 
   // Load the configuration form for this option.
-  if (isset($effect['form callback'])) {
+  if (plugin_get_instance('image', 'effect', $effect['name'], $effect) instanceof ImageConfigurableEffectInterface) {
     $path = 'admin/config/media/image-styles/edit/' . $form_state['image_style']['name'] . '/add/' . $form_state['values']['new'];
     $form_state['redirect'] = array($path, array('query' => array('weight' => $form_state['values']['weight'])));
   }
@@ -336,16 +338,17 @@ function image_effect_form($form, &$form_state, $style, $effect) {
 
   $form_state['image_style'] = $style;
   $form_state['image_effect'] = $effect;
+  $effect_instance = plugin_get_instance('image', 'effect', $effect['name'], $effect);
 
   // If no configuration for this image effect, return to the image style page.
-  if (!isset($effect['form callback'])) {
+  if (!($effect_instance instanceof ImageConfigurableEffectInterface)) {
     drupal_goto('admin/config/media/image-styles/edit/' . $style['name']);
   }
 
   $form['#tree'] = TRUE;
   $form['#attached']['css'][drupal_get_path('module', 'image') . '/image.admin.css'] = array();
 
-  $form['data'] = call_user_func($effect['form callback'], $effect['data']);
+  $form['data'] = $effect_instance->getConfigurationForm();
 
   // Check the URL for a weight, then the image effect, otherwise use default.
   $form['weight'] = array(
diff --git a/core/modules/image/image.api.php b/core/modules/image/image.api.php
index 758d38b..cbf1fb9 100644
--- a/core/modules/image/image.api.php
+++ b/core/modules/image/image.api.php
@@ -11,61 +11,6 @@
  */
 
 /**
- * Define information about image effects provided by a module.
- *
- * This hook enables modules to define image manipulation effects for use with
- * an image style.
- *
- * @return
- *   An array of image effects. This array is keyed on the machine-readable
- *   effect name. Each effect is defined as an associative array containing the
- *   following items:
- *   - "label": The human-readable name of the effect.
- *   - "effect callback": The function to call to perform this image effect.
- *   - "dimensions passthrough": (optional) Set this item if the effect doesn't
- *     change the dimensions of the image.
- *   - "dimensions callback": (optional) The function to call to transform
- *     dimensions for this effect.
- *   - "help": (optional) A brief description of the effect that will be shown
- *     when adding or configuring this image effect.
- *   - "form callback": (optional) The name of a function that will return a
- *     $form array providing a configuration form for this image effect.
- *   - "summary theme": (optional) The name of a theme function that will output
- *     a summary of this image effect's configuration.
- *
- * @see hook_image_effect_info_alter()
- */
-function hook_image_effect_info() {
-  $effects = array();
-
-  $effects['mymodule_resize'] = array(
-    'label' => t('Resize'),
-    'help' => t('Resize an image to an exact set of dimensions, ignoring aspect ratio.'),
-    'effect callback' => 'mymodule_resize_effect',
-    'dimensions callback' => 'mymodule_resize_dimensions',
-    'form callback' => 'mymodule_resize_form',
-    'summary theme' => 'mymodule_resize_summary',
-  );
-
-  return $effects;
-}
-
-/**
- * Alter the information provided in hook_image_effect_info().
- *
- * @param $effects
- *   The array of image effects, keyed on the machine-readable effect name.
- *
- * @see hook_image_effect_info()
- */
-function hook_image_effect_info_alter(&$effects) {
-  // Override the Image module's crop effect with more options.
-  $effects['image_crop']['effect callback'] = 'mymodule_crop_effect';
-  $effects['image_crop']['dimensions callback'] = 'mymodule_crop_dimensions';
-  $effects['image_crop']['form callback'] = 'mymodule_crop_form';
-}
-
-/**
  * Respond to image style updating.
  *
  * This hook enables modules to update settings that might be affected by
diff --git a/core/modules/image/image.effects.inc b/core/modules/image/image.effects.inc
index 35a6a74..e7cabed 100644
--- a/core/modules/image/image.effects.inc
+++ b/core/modules/image/image.effects.inc
@@ -6,62 +6,6 @@
  */
 
 /**
- * Implements hook_image_effect_info().
- */
-function image_image_effect_info() {
-  $effects = array(
-    'image_resize' => array(
-      'label' => t('Resize'),
-      'help' => t('Resizing will make images an exact set of dimensions. This may cause images to be stretched or shrunk disproportionately.'),
-      'effect callback' => 'image_resize_effect',
-      'dimensions callback' => 'image_resize_dimensions',
-      'form callback' => 'image_resize_form',
-      'summary theme' => 'image_resize_summary',
-    ),
-    'image_scale' => array(
-      'label' => t('Scale'),
-      'help' => t('Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.'),
-      'effect callback' => 'image_scale_effect',
-      'dimensions callback' => 'image_scale_dimensions',
-      'form callback' => 'image_scale_form',
-      'summary theme' => 'image_scale_summary',
-    ),
-    'image_scale_and_crop' => array(
-      'label' => t('Scale and crop'),
-      'help' => t('Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.'),
-      'effect callback' => 'image_scale_and_crop_effect',
-      'dimensions callback' => 'image_resize_dimensions',
-      'form callback' => 'image_resize_form',
-      'summary theme' => 'image_resize_summary',
-    ),
-    'image_crop' => array(
-      'label' => t('Crop'),
-      'help' => t('Cropping will remove portions of an image to make it the specified dimensions.'),
-      'effect callback' => 'image_crop_effect',
-      'dimensions callback' => 'image_resize_dimensions',
-      'form callback' => 'image_crop_form',
-      'summary theme' => 'image_crop_summary',
-    ),
-    'image_desaturate' => array(
-      'label' => t('Desaturate'),
-      'help' => t('Desaturate converts an image to grayscale.'),
-      'effect callback' => 'image_desaturate_effect',
-      'dimensions passthrough' => TRUE,
-    ),
-    'image_rotate' => array(
-      'label' => t('Rotate'),
-      'help' => t('Rotating an image may cause the dimensions of an image to increase to fit the diagonal.'),
-      'effect callback' => 'image_rotate_effect',
-      'dimensions callback' => 'image_rotate_dimensions',
-      'form callback' => 'image_rotate_form',
-      'summary theme' => 'image_rotate_summary',
-    ),
-  );
-
-  return $effects;
-}
-
-/**
  * Image effect callback; Resize an image resource.
  *
  * @param $image
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index a0816e4..899e054 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -56,10 +56,10 @@ function image_help($path, $arg) {
     case 'admin/config/media/image-styles':
       return '<p>' . t('Image styles commonly provide thumbnail sizes by scaling and cropping images, but can also add various effects before an image is displayed. When an image is displayed with a style, a new file is created and the original image is left unchanged.') . '</p>';
     case 'admin/config/media/image-styles/edit/%/add/%':
-      $effect = image_effect_definition_load($arg[7]);
+      $effect = _image_effect_definition_load($arg[7]);
       return isset($effect['help']) ? ('<p>' . $effect['help'] . '</p>') : NULL;
     case 'admin/config/media/image-styles/edit/%/effects/%':
-      $effect = ($arg[5] == 'add') ? image_effect_definition_load($arg[6]) : image_effect_load($arg[6], $arg[4]);
+      $effect = ($arg[5] == 'add') ? _image_effect_definition_load($arg[6]) : image_effect_load($arg[6], $arg[4]);
       return isset($effect['help']) ? ('<p>' . $effect['help'] . '</p>') : NULL;
   }
 }
@@ -486,7 +486,7 @@ function image_style_load($name) {
 
   if (!empty($style['effects'])) {
     foreach ($style['effects'] as $ieid => $effect) {
-      $definition = image_effect_definition_load($effect['name']);
+      $definition = _image_effect_definition_load($effect['name']);
       $effect = array_merge($definition, $effect);
       $style['effects'][$ieid] = $effect;
     }
@@ -737,16 +737,7 @@ function image_style_transform_dimensions($style_name, array &$dimensions) {
 
   if (!empty($style['effects'])) {
     foreach ($style['effects'] as $effect) {
-      if (isset($effect['dimensions passthrough'])) {
-        continue;
-      }
-
-      if (isset($effect['dimensions callback'])) {
-        $effect['dimensions callback']($dimensions, $effect['data']);
-      }
-      else {
-        $dimensions['width'] = $dimensions['height'] = NULL;
-      }
+      plugin_get_instance('image', 'effect', $effect['name'], $effect)->transformDimensions($dimensions);
     }
   }
 }
@@ -837,72 +828,21 @@ function image_style_path($style_name, $uri) {
 }
 
 /**
- * Pull in image effects exposed by modules implementing hook_image_effect_info().
- *
- * @return
- *   An array of image effects to be used when transforming images.
- * @see hook_image_effect_info()
- * @see image_effect_definition_load()
+ * Internal helper function to get the definitions for all image effect plugins.
  */
-function image_effect_definitions() {
-  global $language_interface;
-
-  // hook_image_effect_info() includes translated strings, so each language is
-  // cached separately.
-  $langcode = $language_interface->langcode;
-
-  $effects = &drupal_static(__FUNCTION__);
-
-  if (!isset($effects)) {
-    if ($cache = cache()->get("image_effects:$langcode") && !empty($cache->data)) {
-      $effects = $cache->data;
-    }
-    else {
-      $effects = array();
-      include_once DRUPAL_ROOT . '/core/modules/image/image.effects.inc';
-      foreach (module_implements('image_effect_info') as $module) {
-        foreach (module_invoke($module, 'image_effect_info') as $name => $effect) {
-          // Ensure the current toolkit supports the effect.
-          $effect['module'] = $module;
-          $effect['name'] = $name;
-          $effect['data'] = isset($effect['data']) ? $effect['data'] : array();
-          $effects[$name] = $effect;
-        }
-      }
-      uasort($effects, '_image_effect_definitions_sort');
-      drupal_alter('image_effect_info', $effects);
-      cache()->set("image_effects:$langcode", $effects);
-    }
+function _image_effect_definitions() {
+  $definitions = array();
+  foreach (plugin_get_type('image', 'effect')->getPluginIds() as $effect_name) {
+    $definitions[$effect_name] = _image_effect_definition_load($effect_name);
   }
-
-  return $effects;
+  return $definitions;
 }
 
 /**
- * Load the definition for an image effect.
- *
- * The effect definition is a set of core properties for an image effect, not
- * containing any user-settings. The definition defines various functions to
- * call when configuring or executing an image effect. This loader is mostly for
- * internal use within image.module. Use image_effect_load() or
- * image_style_load() to get image effects that contain configuration.
- *
- * @param $effect
- *   The name of the effect definition to load.
- * @return
- *   An array containing the image effect definition with the following keys:
- *   - "effect": The unique name for the effect being performed. Usually prefixed
- *     with the name of the module providing the effect.
- *   - "module": The module providing the effect.
- *   - "help": A description of the effect.
- *   - "function": The name of the function that will execute the effect.
- *   - "form": (optional) The name of a function to configure the effect.
- *   - "summary": (optional) The name of a theme function that will display a
- *     one-line summary of the effect. Does not include the "theme_" prefix.
+ * Internal helper function to get the definition for an image effect plugin.
  */
-function image_effect_definition_load($effect) {
-  $definitions = image_effect_definitions();
-  return isset($definitions[$effect]) ? $definitions[$effect] : FALSE;
+function _image_effect_definition_load($effect_name) {
+  return plugin_get_plugin('image', 'effect', $effect_name)->getDefinition();
 }
 
 /**
@@ -930,7 +870,7 @@ function image_effects() {
       ->execute();
     foreach ($result as $effect) {
       $effect['data'] = unserialize($effect['data']);
-      $definition = image_effect_definition_load($effect['name']);
+      $definition = _image_effect_definition_load($effect['name']);
       // Do not load image effects whose definition cannot be found.
       if ($definition) {
         $effect = array_merge($definition, $effect);
@@ -960,12 +900,11 @@ function image_effects() {
  *   the image effect array. Returns FALSE if the specified effect cannot be
  *   found.
  * @see image_style_load()
- * @see image_effect_definition_load()
  */
 function image_effect_load($ieid, $style_name) {
   if (($style = image_style_load($style_name)) && isset($style['effects'][$ieid])) {
     $effect = $style['effects'][$ieid];
-    $definition = image_effect_definition_load($effect['name']);
+    $definition = _image_effect_definition_load($effect['name']);
     $effect = array_merge($definition, $effect);
     // @todo The effect's key name within the style is unknown. It *should* be
     //   identical to the ieid, but that is in no way guaranteed. And of course,
@@ -1041,8 +980,7 @@ function image_effect_delete($style_name, $effect) {
  */
 function image_effect_apply($image, $effect) {
   module_load_include('inc', 'image', 'image.effects');
-  $function = $effect['effect callback'];
-  return $function($image, $effect['data']);
+  return plugin_get_instance('image', 'effect', $effect['name'], $effect)->applyEffect($image);
 }
 
 /**
@@ -1104,12 +1042,3 @@ function image_filter_keyword($value, $current_pixels, $new_pixels) {
   }
   return $value;
 }
-
-/**
- * Internal function for sorting image effect definitions through uasort().
- *
- * @see image_effect_definitions()
- */
-function _image_effect_definitions_sort($a, $b) {
-  return strcasecmp($a['name'], $b['name']);
-}
diff --git a/core/modules/image/image.test b/core/modules/image/image.test
index 2c422a7..3ab1ec0 100644
--- a/core/modules/image/image.test
+++ b/core/modules/image/image.test
@@ -18,7 +18,6 @@
  *   image_style_delete()
  *   image_style_options()
  *   image_style_flush()
- *   image_effect_definition_load()
  *   image_effect_load()
  *   image_effect_save()
  *   image_effect_delete()
diff --git a/core/modules/image/lib/Drupal/image/Effect/CropEffect.php b/core/modules/image/lib/Drupal/image/Effect/CropEffect.php
new file mode 100644
index 0000000..853840c
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/CropEffect.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\CropEffect.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * @todo So far this class just contains wrappers to procedural functions. Move
+ *   the function bodies into here and refactor them for OOP.
+ */
+class CropEffect implements ImageConfigurableEffectInterface {
+
+  protected $data = array();
+
+  function __construct(array $data) {
+    $this->data = $data;
+  }
+
+  function applyEffect(&$image) {
+    return image_crop_effect($image, $this->data);
+  }
+
+  function transformDimensions(array &$dimensions) {
+    return image_resize_dimensions($dimensions, $this->data);
+  }
+
+  function getConfigurationForm() {
+    return image_crop_form($this->data);
+  }
+
+  function viewSummary() {
+    return array(
+      '#theme' => 'image_crop_summary',
+      '#data' => $this->data,
+    );
+  }
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/DesaturateEffect.php b/core/modules/image/lib/Drupal/image/Effect/DesaturateEffect.php
new file mode 100644
index 0000000..0364e98
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/DesaturateEffect.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\DesaturateEffect.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * @todo So far this class just contains wrappers to procedural functions. Move
+ *   the function bodies into here and refactor them for OOP.
+ */
+class DesaturateEffect implements ImageEffectInterface {
+
+  protected $data = array();
+
+  function __construct(array $data) {
+    $this->data = $data;
+  }
+
+  function applyEffect(&$image) {
+    return image_desaturate_effect($image, $this->data);
+  }
+
+  function transformDimensions(array &$dimensions) {
+    return;
+  }
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/ImageConfigurableEffectInterface.php b/core/modules/image/lib/Drupal/image/Effect/ImageConfigurableEffectInterface.php
new file mode 100644
index 0000000..38b798c
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/ImageConfigurableEffectInterface.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\ImageConfigurableEffectInterface.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * Defines the common interface for image effects that are configurable.
+ */
+interface ImageConfigurableEffectInterface extends ImageEffectInterface {
+
+  function getConfigurationForm();
+
+  function viewSummary();
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/ImageEffectInterface.php b/core/modules/image/lib/Drupal/image/Effect/ImageEffectInterface.php
new file mode 100644
index 0000000..95d28ff
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/ImageEffectInterface.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\ImageEffectInterface.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * Defines the common interface for image effects.
+ */
+interface ImageEffectInterface {
+
+  function applyEffect(&$image);
+
+  function transformDimensions(array &$dimensions);
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/ResizeEffect.php b/core/modules/image/lib/Drupal/image/Effect/ResizeEffect.php
new file mode 100644
index 0000000..fb08d5c
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/ResizeEffect.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\ResizeEffect.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * @todo So far this class just contains wrappers to procedural functions. Move
+ *   the function bodies into here and refactor them for OOP.
+ */
+class ResizeEffect implements ImageConfigurableEffectInterface {
+
+  protected $data = array();
+
+  function __construct(array $data) {
+    $this->data = $data;
+  }
+
+  function applyEffect(&$image) {
+    return image_resize_effect($image, $this->data);
+  }
+
+  function transformDimensions(array &$dimensions) {
+    return image_resize_dimensions($dimensions, $this->data);
+  }
+
+  function getConfigurationForm() {
+    return image_resize_form($this->data);
+  }
+
+  function viewSummary() {
+    return array(
+      '#theme' => 'image_resize_summary',
+      '#data' => $this->data,
+    );
+  }
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/RotateEffect.php b/core/modules/image/lib/Drupal/image/Effect/RotateEffect.php
new file mode 100644
index 0000000..8e498b0
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/RotateEffect.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\RotateEffect.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * @todo So far this class just contains wrappers to procedural functions. Move
+ *   the function bodies into here and refactor them for OOP.
+ */
+class RotateEffect implements ImageConfigurableEffectInterface {
+
+  protected $data = array();
+
+  function __construct(array $data) {
+    $this->data = $data;
+  }
+
+  function applyEffect(&$image) {
+    return image_rotate_effect($image, $this->data);
+  }
+
+  function transformDimensions(array &$dimensions) {
+    return image_rotate_dimensions($dimensions, $this->data);
+  }
+
+  function getConfigurationForm() {
+    return image_rotate_form($this->data);
+  }
+
+  function viewSummary() {
+    return array(
+      '#theme' => 'image_rotate_summary',
+      '#data' => $this->data,
+    );
+  }
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/ScaleAndCropEffect.php b/core/modules/image/lib/Drupal/image/Effect/ScaleAndCropEffect.php
new file mode 100644
index 0000000..087cd18
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/ScaleAndCropEffect.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\ScaleAndCropEffect.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * @todo So far this class just contains wrappers to procedural functions. Move
+ *   the function bodies into here and refactor them for OOP.
+ */
+class ScaleAndCropEffect implements ImageConfigurableEffectInterface {
+
+  protected $data = array();
+
+  function __construct(array $data) {
+    $this->data = $data;
+  }
+
+  function applyEffect(&$image) {
+    return image_scale_and_crop_effect($image, $this->data);
+  }
+
+  function transformDimensions(array &$dimensions) {
+    return image_resize_dimensions($dimensions, $this->data);
+  }
+
+  function getConfigurationForm() {
+    return image_resize_form($this->data);
+  }
+
+  function viewSummary() {
+    return array(
+      '#theme' => 'image_resize_summary',
+      '#data' => $this->data,
+    );
+  }
+
+}
diff --git a/core/modules/image/lib/Drupal/image/Effect/ScaleEffect.php b/core/modules/image/lib/Drupal/image/Effect/ScaleEffect.php
new file mode 100644
index 0000000..a72d788
--- /dev/null
+++ b/core/modules/image/lib/Drupal/image/Effect/ScaleEffect.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\image\Effect\ScaleEffect.
+ */
+
+namespace Drupal\image\Effect;
+
+/**
+ * @todo So far this class just contains wrappers to procedural functions. Move
+ *   the function bodies into here and refactor them for OOP.
+ */
+class ScaleEffect implements ImageConfigurableEffectInterface {
+
+  protected $data = array();
+
+  function __construct(array $data) {
+    $this->data = $data;
+  }
+
+  function applyEffect(&$image) {
+    return image_scale_effect($image, $this->data);
+  }
+
+  function transformDimensions(array &$dimensions) {
+    return image_scale_dimensions($dimensions, $this->data);
+  }
+
+  function getConfigurationForm() {
+    return image_scale_form($this->data);
+  }
+
+  function viewSummary() {
+    return array(
+      '#theme' => 'image_scale_summary',
+      '#data' => $this->data,
+    );
+  }
+
+}
