diff --git a/includes/rules.core.inc b/includes/rules.core.inc
index 1edef43..050bdb8 100644
--- a/includes/rules.core.inc
+++ b/includes/rules.core.inc
@@ -30,6 +30,11 @@ class RulesEntityController extends EntityAPIControllerExportable {
         ->condition('id', $entity->id)
         ->execute()
         ->fetchCol('tag');
+      $entity->dependencies = db_select('rules_dependencies')
+        ->fields('rules_dependencies', array('module'))
+        ->condition('id', $entity->id)
+        ->execute()
+        ->fetchCol('module');
       $entities[$entity->id] = $entity;
     }
     $queried_entities = $entities;
@@ -104,6 +109,7 @@ class RulesEntityController extends EntityAPIControllerExportable {
           return FALSE;
         }
       }
+      $config->dependencies = $export['REQUIRES'];
     }
     $config->import($export);
     return $config;
@@ -117,6 +123,7 @@ class RulesEntityController extends EntityAPIControllerExportable {
     if ($rules_config instanceof RulesTriggerableInterface) {
       $this->storeEvents($rules_config);
     }
+    $this->storeDependencies($rules_config);
     return $return;
   }
 
@@ -153,6 +160,22 @@ class RulesEntityController extends EntityAPIControllerExportable {
     }
   }
 
+  protected function storeDependencies($rules_config) {
+    db_delete('rules_dependencies')
+      ->condition('id', $rules_config->id)
+      ->execute();
+    if (!empty($rules_config->dependencies)) {
+      foreach ($rules_config->dependencies as $dependency) {
+        db_insert('rules_dependencies')
+          ->fields(array(
+          'id' => $rules_config->id,
+          'module' => $dependency,
+        ))
+        ->execute();
+      }
+    }
+  }
+
   /**
    * Overridden to support tags and events in $conditions.
    * @see EntityAPIControllerExportable::buildQuery()
@@ -191,6 +214,9 @@ class RulesEntityController extends EntityAPIControllerExportable {
         db_delete('rules_tags')
           ->condition('id', $config->id)
           ->execute();
+        db_delete('rules_dependencies')
+          ->condition('id', $config->id)
+          ->execute();
       }
     }
     return parent::delete($ids, $transaction);
@@ -613,7 +639,10 @@ abstract class RulesPlugin extends RulesExtendable {
   }
 
   /**
-   * Returns an array of required modules.
+   * Calculates an array of required modules.
+   *
+   * You can use $this->dependencies to access dependencies for saved
+   * configurations.
    */
   public function dependencies() {
     $this->processSettings();
@@ -691,8 +720,11 @@ abstract class RulesPlugin extends RulesExtendable {
   public function integrityCheck() {
     // First process the settings if not done yet.
     $this->processSettings();
-    // Check dependencies.
-    foreach ($this->dependencies() as $module) {
+    // Check dependencies using the pre-calculated dependencies stored in
+    // $this->dependencies. Fail back to calculation them on the fly, e.g.
+    // during creation.
+    $dependencies = empty($this->dependencies) ? $this->dependencies() : $this->dependencies;
+    foreach ($dependencies as $module) {
       if (!module_exists($module)) {
         throw new RulesDependencyException(t('Missing required module %name.', array('%name' => $module)));
       }
@@ -871,9 +903,16 @@ abstract class RulesPlugin extends RulesExtendable {
       return $this->parent->save($name, $module);
     }
     else {
-      // Make sure all element settings are processed before we save.
-      $this->processSettings();
-
+      // In case the config is not dirty, pre-calculate the dependencies for
+      // later checking. Note that this also triggers processing settings if
+      // necessary.
+      // @see rules_modules_enabled()
+      // However, this operation depends on a fully built Rules-cache, so skip
+      // it when entities in code are imported to the database.
+      // @see _rules_rebuild_cache()
+      if (empty($this->dirty) && empty($this->is_rebuild)) {
+        $this->dependencies = $this->dependencies();
+      }
       $this->plugin = $this->itemName;
       $this->name = isset($name) ? $name : $this->name;
       $this->module = !isset($this->module) || $module != 'rules' ? $module : $this->module;
@@ -1178,16 +1217,29 @@ abstract class RulesPlugin extends RulesExtendable {
     parent::rebuildCache($itemInfo, $cache);
     if (!empty($this->itemInfo['component'])) {
       // Just move each component into the cache.
-      $components = rules_config_load_multiple(FALSE, array('plugin' => $this->itemName));
+      $components = rules_config_load_multiple(FALSE, array('plugin' => $this->itemName, 'dirty' => 0));
 
       foreach ($components as $id => $component) {
-        // Clone the component to avoid modules getting the to be cached
-        // version from the static loading cache.
-        $component = clone $component;
-        $component->optimize();
-        // Allow modules to alter the cached component.
-        drupal_alter('rules_component', $this->itemName, $component);
-        rules_set_cache('comp_' . $component->name, $component);
+        try {
+          $component->integrityCheck();
+          // Clone the component to avoid modules getting the to be cached
+          // version from the static loading cache.
+          $component = clone $component;
+          $component->optimize();
+          // Allow modules to alter the cached component.
+          drupal_alter('rules_component', $this->itemName, $component);
+          rules_set_cache('comp_' . $component->name, $component);
+        }
+        catch (RulesIntegrityException $e) {
+          // Mark the component as dirty and do not cache it.
+          $component->dirty = TRUE;
+          db_update('rules_config')
+            ->fields(array('dirty' => 1))
+            ->condition('id', $component->id)
+            ->execute();
+          $variables = array('%component' => $component->label(), '%name' => $component->name, '!message' => $e->getMessage());
+          watchdog('rules', 'The component %component (%name) fails the integrity check and cannot be executed. Error: !message', $variables, WATCHDOG_ERROR);
+        }
       }
     }
   }
diff --git a/includes/rules.plugins.inc b/includes/rules.plugins.inc
index 8b68b5c..31e93a8 100644
--- a/includes/rules.plugins.inc
+++ b/includes/rules.plugins.inc
@@ -693,19 +693,37 @@ class RulesEventSet extends RulesRuleSet {
         'variables' => isset($info['arguments']) ? $info['arguments'] : array(),
       );
       // Add all rules associated with this event to an EventSet for caching.
-      if ($rules = rules_config_load_multiple(FALSE, array('event' => $name, 'active' => TRUE))) {
+      if ($rules = rules_config_load_multiple(FALSE, array('event' => $name, 'active' => TRUE, 'dirty' => 0))) {
         $event = new RulesEventSet($info);
         $event->name = $name;
         foreach ($rules as $rule) {
-          // Clone the rule to avoid modules getting the changed version from
-          // the static cache.
-          $event->rule(clone $rule);
+          try {
+            $rule->integrityCheck();
+            // Clone the rule to avoid modules getting the changed version from
+            // the static cache.
+            $event->rule(clone $rule);
+          }
+          catch (RulesIntegrityException $e) {
+            // Mark the rule as dirty and do not cache it.
+            $rule->dirty = TRUE;
+            db_update('rules_config')
+              ->fields(array('dirty' => 1))
+              ->condition('id', $rule->id)
+              ->execute();
+            $variables = array('%rule' => $rule->label(), '%name' => $rule->name, '!message' => $e->getMessage());
+            watchdog('rules', 'The rule %rule (%name) fails the integrity check and cannot be executed. Error: !message', $variables, WATCHDOG_ERROR);
+          }
+        }
+        if ($event->children) {
+          $event->sortChildren();
+          $event->optimize();
+          // Allow modules to alter the cached event set.
+          drupal_alter('rules_event_set', $name, $event);
+          rules_set_cache('event_' . $name, $event);
+        }
+        else {
+          $empty[] = $name;
         }
-        $event->sortChildren();
-        $event->optimize();
-        // Allow modules to alter the cached event set.
-        drupal_alter('rules_event_set', $name, $event);
-        rules_set_cache('event_' . $name, $event);
       }
       else {
         $empty[] = $name;
diff --git a/modules/rules_core.rules.inc b/modules/rules_core.rules.inc
index c2c28ed..b59f8d7 100644
--- a/modules/rules_core.rules.inc
+++ b/modules/rules_core.rules.inc
@@ -253,6 +253,44 @@ function rules_element_invoke_component_operations(RulesPlugin $element) {
 }
 
 /**
+ * Validate callback to make sure the invoked component exists and is not dirty.
+ */
+function rules_element_invoke_component_validate(RulesPlugin $element) {
+  $info = $element->info();
+  rules_element_validate_component($info['#config_name'], $element);
+}
+
+/**
+ * Helper for validating that a used component passes the integrity check.
+ *
+ * @see rules_scheduler_action_schedule_validate()
+ */
+function rules_element_validate_component($name, $element) {
+  $recursion = &drupal_static(__FUNCTION__, array());
+
+  // Bail out in case of recursive checks to avoid infinite loops. This is
+  // necessary when handling components that directly or indirectly call itself.
+  if (!empty($recursion[$element->root()->name])) {
+    return;
+  }
+  $recursion[$element->root()->name] = TRUE;
+
+  $component = rules_config_load($name);
+  if (!$component) {
+    unset($recursion[$element->root()->name]);
+    throw new RulesIntegrityException(t('The component %config does not exist.', array('%config' => $name)), $element);
+  }
+  try {
+    $component->integrityCheck();
+  }
+  catch (RulesIntegrityException $e) {
+    unset($recursion[$element->root()->name]);
+    throw new RulesIntegrityException(t('The component %config fails the integrity check. Error: !message', array('%config' => $name, '!message' => $e->getMessage())), $element);
+  }
+  unset($recursion[$element->root()->name]);
+}
+
+/**
  * Implements the features export callback of the RulesPluginFeaturesIntegrationInterace.
  */
 function rules_element_invoke_component_features_export(&$export, &$pipe, $module_name = '', $element) {
diff --git a/rules.install b/rules.install
index 9902a7f..762710f 100644
--- a/rules.install
+++ b/rules.install
@@ -74,6 +74,13 @@ function rules_schema() {
         'size' => 'tiny',
         'description' => 'The exportable status of the entity.',
       ),
+      'dirty' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Dirty configurations fail the integrity check, e.g. due to missing dependencies.',
+      ),
       'module' => array(
         'description' => 'The name of the providing module if the entity has been defined in code.',
         'type' => 'varchar',
@@ -137,6 +144,29 @@ function rules_schema() {
       'id' => array('rules_config' => 'id'),
     ),
   );
+  $schema['rules_dependencies'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The primary identifier of the configuration.',
+      ),
+      'module' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'description' => 'The name of the module that is required for the configuration.',
+      ),
+    ),
+    'primary key' => array('id', 'module'),
+    'indexes' => array(
+      'module' => array('module'),
+    ),
+    'foreign keys' => array(
+      'id' => array('rules_config' => 'id'),
+    ),
+  );
   $schema['cache_rules'] = drupal_get_schema_unprocessed('system', 'cache');
   $schema['cache_rules']['description'] = 'Cache table for the rules engine to store configured items.';
   return $schema;
@@ -322,3 +352,43 @@ function rules_update_7204() {
     db_create_table('rules_tags', $schema['rules_tags']);
   }
 }
+
+/**
+ * Add the rules_dependencies table and the rules_config.dirty column.
+ */
+function rules_update_7205() {
+  if (!db_table_exists('rules_dependencies')) {
+    $schema['rules_dependencies'] = array(
+      'fields' => array(
+        'id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'The primary identifier of the configuration.',
+        ),
+        'module' => array(
+          'type' => 'varchar',
+          'length' => '255',
+          'not null' => TRUE,
+          'description' => 'The name of the module that is required for the configuration.',
+        ),
+      ),
+      'primary key' => array('id', 'module'),
+      'indexes' => array(
+        'module' => array('module'),
+      ),
+      'foreign keys' => array(
+        'id' => array('rules_config' => 'id'),
+      ),
+    );
+    db_create_table('rules_dependencies', $schema['rules_dependencies']);
+  }
+  if (!db_field_exists('rules_config', 'dirty')) {
+    db_add_field('rules_config', 'dirty', array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'default' => 0,
+      'size' => 'tiny',
+    ));
+  }
+}
diff --git a/rules.module b/rules.module
index d4159de..f97c136 100644
--- a/rules.module
+++ b/rules.module
@@ -260,9 +260,18 @@ function &rules_get_cache($cid = 'data') {
 }
 
 /**
- * Rebuilds the main rules cache ('data') and invokes rebuildCache() methods on
- * all mentioned class, which in turn rebuild their own caches or update the
- * main cache.
+ * Rebuilds the rules cache.
+ *
+ * This rebuilds the rules 'data' cache and invokes rebuildCache() methods on
+ * all plugin classes, which in turn rebuild their own caches or update the
+ * main cache. The cache is rebuilt in the order the plugins are defined.
+ *
+ * Note that building the action/condition info cache triggers loading of all
+ * components, thus depends on entity-loading and so syncing entities in code
+ * to the database.
+ *
+ * @see rules_rules_plugin_info()
+ * @see entity_defaults_rebuild()
  */
 function _rules_rebuild_cache(&$cache) {
   foreach(array('data_info', 'plugin_info') as $hook) {
@@ -733,7 +742,7 @@ function rules_invoke_event() {
   unset($args[0]);
   // For invoking the rules event we directly acccess the global $conf. This is
   // fast without having to introduce another static cache.
-  if (!isset($conf['rules_empty_sets'][$event_name]) && $event = rules_get_cache('event_' . $event_name)) {
+  if (!defined('MAINTENANCE_MODE') && !isset($conf['rules_empty_sets'][$event_name]) && $event = rules_get_cache('event_' . $event_name)) {
     $event->executeByArgs($args);
   }
 }
@@ -760,7 +769,7 @@ function rules_invoke_event_by_args($event_name, $args = array()) {
 
   // For invoking the rules event we directly acccess the global $conf. This is
   // fast without having to introduce another static cache.
-  if (!isset($conf['rules_empty_sets'][$event_name]) && $event = rules_get_cache('event_' . $event_name)) {
+  if (!defined('MAINTENANCE_MODE') && !isset($conf['rules_empty_sets'][$event_name]) && $event = rules_get_cache('event_' . $event_name)) {
     $event->executeByArgs($args);
   }
 }
@@ -774,7 +783,8 @@ function rules_invoke_event_by_args($event_name, $args = array()) {
  *   Pass further parameters as required for the invoked component.
  *
  * @return
- *   The variables as provided by the component.
+ *   An array of variables as provided by the component, or FALSE in case the
+ *   component could not be executed.
  */
 function rules_invoke_component() {
   $args = func_get_args();
@@ -782,6 +792,7 @@ function rules_invoke_component() {
   if ($component = rules_get_cache('comp_' . $name)) {
     return $component->executeByArgs($args);
   }
+  return FALSE;
 }
 
 /**
@@ -794,6 +805,7 @@ function rules_invoke_component() {
  *   The key used for the comparison.
  * @param $value
  *   The value to compare the array's entry to.
+ *
  * @return array
  *   The filtered array.
  */
@@ -1087,6 +1099,37 @@ function rules_element_info() {
  * Implements hook_modules_enabled().
  */
 function rules_modules_enabled($modules) {
+  // Re-enable Rules configurations that are dirty, because they require one of
+  // the enabled the modules.
+  $query = db_select('rules_dependencies', 'rd');
+  $query->join('rules_config', 'rc', 'rd.id = rc.id');
+  $query->fields('rd', array('id'))
+        ->condition('rd.module', $modules, 'IN')
+        ->condition('rc.dirty', 1);
+  $ids = $query->execute()->fetchCol();
+
+  // If there are some configurations that might work again, re-check all dirty
+  // configurations as others might work again too, e.g. consider a rule that is
+  // dirty because it requires a dirty component.
+  if ($ids) {
+    $rules_configs = rules_config_load_multiple(FALSE, array('dirty' => 1));
+    foreach ($rules_configs as $rules_config) {
+      try {
+        $rules_config->integrityCheck();
+        // If no exceptions were thrown we can set the configuration back to OK.
+        db_update('rules_config')
+          ->fields(array('dirty' => 0))
+          ->condition('id', $rules_config->id)
+          ->execute();
+        if ($rules_config->active) {
+          drupal_set_message(t('All dependencies for the Rules configuration %config are met again, so it has been re-activated.', array('%config' => $rules_config->label())));
+        }
+      }
+      catch (RulesIntegrityException $e) {
+        // The rule is still dirty, so do nothing.
+      }
+    }
+  }
   rules_clear_cache();
 }
 
@@ -1094,8 +1137,35 @@ function rules_modules_enabled($modules) {
  * Implements hook_modules_disabled().
  */
 function rules_modules_disabled($modules) {
+  // Disable Rules configurations that depend on one of the disabled modules.
+  $query = db_select('rules_dependencies', 'rd');
+  $query->join('rules_config', 'rc', 'rd.id = rc.id');
+  $query->fields('rd', array('id'))
+        ->distinct()
+        ->condition('rd.module', $modules, 'IN')
+        ->condition('rc.dirty', 0);
+  $ids = $query->execute()->fetchCol();
+
+  if (!empty($ids)) {
+    db_update('rules_config')
+      ->fields(array('dirty' => 1))
+      ->condition('id', $ids, 'IN')
+      ->execute();
+    // Tell the user about enabled rules that have been marked as dirty.
+    $count = db_select('rules_config', 'r')
+      ->fields('r')
+      ->condition('id', $ids, 'IN')
+      ->condition('active', 1)
+      ->execute()->rowCount();
+    if ($count > 0) {
+      $message = format_plural($count,
+        '1 Rules configuration requires some of the disabled modules to function and cannot be executed any more.',
+        '@count Rules configuration require some of the disabled modules to function and cannot be executed any more.'
+      );
+      drupal_set_message($message, 'warning');
+    }
+  }
   rules_clear_cache();
-  //TODO: Disable configs with now broken dependencies?
 }
 
 /**
diff --git a/rules_scheduler/rules_scheduler.rules.inc b/rules_scheduler/rules_scheduler.rules.inc
index feb9234..fc727fa 100644
--- a/rules_scheduler/rules_scheduler.rules.inc
+++ b/rules_scheduler/rules_scheduler.rules.inc
@@ -101,15 +101,27 @@ function rules_scheduler_action_schedule($args, $element) {
  * Info alteration callback for the schedule action.
  */
 function rules_scheduler_action_schedule_info_alter(&$element_info, RulesPlugin $element) {
-  if (isset($element->settings['component']) && $component = rules_get_cache('comp_' . $element->settings['component'])) {
-    // Add in the needed parameters.
-    foreach ($component->parameterInfo() as $name => $info) {
-      $element_info['parameter']['param_' . $name] = $info;
+  if (isset($element->settings['component'])) {
+    // If run during a cache rebuild the cache might not be instantiated yet,
+    // so fail back to loading the component from database.
+    if (($component = rules_get_cache('comp_' . $element->settings['component'])) || $component = rules_config_load($element->settings['component'])) {
+      // Add in the needed parameters.
+      foreach ($component->parameterInfo() as $name => $info) {
+        $element_info['parameter']['param_' . $name] = $info;
+      }
     }
   }
 }
 
 /**
+ * Validate callback for the schedule action to make sure the component exists and is not dirty.
+ */
+function rules_scheduler_action_schedule_validate(RulesPlugin $element) {
+  module_load_include('inc', 'rules', 'modules/rules_core.rules');
+  rules_element_validate_component($element->settings['component'], $element);
+}
+
+/**
  * Help for the schedule action.
  */
 function rules_scheduler_action_schedule_help() {
diff --git a/tests/rules.test b/tests/rules.test
index 8162e0c..4b70882 100644
--- a/tests/rules.test
+++ b/tests/rules.test
@@ -77,11 +77,63 @@ class RulesTestCase extends DrupalWebTestCase {
   }
 
   /**
-   * Test getting dependencies.
+   * Test handling dependencies.
    */
   function testdependencies() {
     $action = rules_action('rules_node_publish_action');
     $this->assertEqual($action->dependencies(), array('rules_test'), 'Providing module is returned as dependency.');
+
+    // Test handling unmet dependencies.
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue(in_array('comment', $rule->dependencies) && !$rule->dirty, 'Dependencies have been imported.');
+
+    // Remove the required comment module and make sure the rule is dirty then.
+    module_disable(array('comment'));
+    rules_clear_cache(TRUE);
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue($rule->dirty, 'Rule has been marked as dirty');
+
+    // Now try re-enabling.
+    module_enable(array('comment'));
+    rules_clear_cache(TRUE);
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue(!$rule->dirty, 'Rule has been marked as not dirty again.');
+
+    // Test it with components.
+    module_enable(array('path'));
+    $action_set = rules_action_set(array('node' => array('type' => 'node')));
+    $action_set->action('node_path_alias');
+    $action_set->save('rules_test_alias');
+
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->action('component_rules_test_alias');
+    $rule->integrityCheck();
+    $rule->save('rules_test_rule');
+    rules_clear_cache(TRUE);
+
+    $rule = rules_config_load('rules_test_rule');
+    $component = rules_config_load('rules_test_alias');
+    $this->assertTrue(in_array('path', $component->dependencies) && !$rule->dirty && !$component->dirty, 'Component has path module dependency.');
+
+    // Now disable path module and make sure both configs are marked as dirty.
+    module_disable(array('path'));
+    rules_clear_cache(TRUE);
+    $rule = rules_config_load('rules_test_rule');
+    $component = rules_config_load('rules_test_alias');
+
+    $node = NULL;
+    $result = rules_invoke_component('rules_test_alias', $node);
+    $this->assertTrue($result === FALSE, 'Unable to execute a dirty component.');
+
+    $this->assertTrue($component->dirty, 'Component has been marked as dirty');
+    $this->assertTrue($rule->dirty, 'Rule has been marked as dirty');
+
+    module_enable(array('path'));
+    rules_clear_cache(TRUE);
+    $rule = rules_config_load('rules_test_rule');
+    $component = rules_config_load('rules_test_alias');
+    $this->assertTrue(!$component->dirty, 'Component has been marked as not dirty again.');
+    $this->assertTrue(!$rule->dirty, 'Rule has been marked as not dirty again.');
   }
 
   /**
@@ -325,9 +377,10 @@ class RulesTestCase extends DrupalWebTestCase {
          ->execute($node->nid);
 
     RulesLog::logger()->checkLog();
-    $msg = drupal_get_messages();
+    $msg = drupal_get_messages('status');
+    $last_msg = array_pop($msg['status']);
     $wrapper = entity_metadata_wrapper('node', $node);
-    $this->assertEqual($msg['status'][0], $wrapper->body->value->value(array('sanitize' => TRUE)), 'Data selector for getting parameter applied.');
+    $this->assertEqual($last_msg, $wrapper->body->value->value(array('sanitize' => TRUE)), 'Data selector for getting parameter applied.');
 
     // Get a "reference" on the same object as returned by node_load().
     $node = node_load($node->nid);
