diff --git a/core/modules/entity/lib/Drupal/entity/EntityFieldQuery.php b/core/modules/entity/lib/Drupal/entity/EntityFieldQuery.php
index fc283fc..e7ac424 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityFieldQuery.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityFieldQuery.php
@@ -148,6 +148,13 @@ class EntityFieldQuery {
   public $fields = array();
 
   /**
+   * A list of used properties keyed by group.
+   *
+   * @var array
+   */
+  public $properties = array();
+
+  /**
    * TRUE if this is a count query, FALSE if it isn't.
    *
    * @var boolean
@@ -420,19 +427,48 @@ class EntityFieldQuery {
    *     of the same type as the column.
    *   The operator can be omitted, and will default to 'IN' if the value is an
    *   array, or to '=' otherwise.
+   * @param $langcode_group
+   *   An arbitrary identifier: conditions in the same group must have the same
+   *   $langcode_group.
    *
    * @return Drupal\entity\EntityFieldQuery
    *   The called object.
    */
-  public function propertyCondition($column, $value, $operator = NULL) {
+  public function propertyCondition($column, $value, $operator = NULL, $langcode_group = NULL) {
+    $group = !empty($langcode_group) ? $langcode_group : 0;
+    $this->properties[$group][$column] = $column;
     $this->propertyConditions[] = array(
       'column' => $column,
       'value' => $value,
       'operator' => $operator,
+      'langcode_group' => $group,
     );
     return $this;
   }
 
+
+  /**
+   * Adds a condition on the property language.
+   *
+   * @param $langcode
+   *   The language code that the properties belonging to the language group
+   *   should match.
+   * @param $operator
+   *   The operator to be used to test the given value.
+   * @param $langcode_group
+   *   An arbitrary identifier: conditions in the same group must have the same
+   *   $langcode_group.
+   *
+   * @return Drupal\entity\EntityFieldQuery
+   *   The called object.
+   *
+   * @see Drupal\entity\EntityFieldQuery::addFieldCondition()
+   * @see Drupal\entity\EntityFieldQuery::deleted()
+   */
+  public function propertyLanguageCondition($langcode = NULL, $operator = NULL, $langcode_group = NULL) {
+    return $this->propertyCondition('langcode', $langcode, $operator, $langcode_group);
+  }
+
   /**
    * Orders the result set by entity-generic metadata.
    *
@@ -515,15 +551,19 @@ class EntityFieldQuery {
    *   The column on which to order.
    * @param $direction
    *   The direction to sort. Legal values are "ASC" and "DESC".
+   * @param $langcode_group
+   *   An arbitrary identifier: conditions in the same group must have the same
+   *   $langcode_group.
    *
    * @return Drupal\entity\EntityFieldQuery
    *   The called object.
    */
-  public function propertyOrderBy($column, $direction = 'ASC') {
+  public function propertyOrderBy($column, $direction = 'ASC', $langcode_group = NULL) {
     $this->order[] = array(
       'type' => 'property',
       'specifier' => $column,
       'direction' => $direction,
+      'langcode_group' => !empty($langcode_group) ? $langcode_group : 0,
     );
     return $this;
   }
@@ -797,26 +837,27 @@ class EntityFieldQuery {
     if (empty($this->entityConditions['entity_type'])) {
       throw new EntityFieldQueryException(t('For this query an entity type must be specified.'));
     }
+
     $entity_type = $this->entityConditions['entity_type']['value'];
     $entity_info = entity_get_info($entity_type);
     if (empty($entity_info['base table'])) {
       throw new EntityFieldQueryException(t('Entity %entity has no base table.', array('%entity' => $entity_type)));
     }
+
     $base_table = $entity_info['base table'];
-    $base_table_schema = drupal_get_schema($base_table);
     $select_query = db_select($base_table);
     $select_query->addExpression(':entity_type', 'entity_type', array(':entity_type' => $entity_type));
+    $sql_field = $entity_info['entity keys']['id'];
+
     // Process the property conditions.
-    foreach ($this->propertyConditions as $property_condition) {
-      $this->addCondition($select_query, $base_table . '.' . $property_condition['column'], $property_condition);
-    }
-    // Process the four possible entity condition.
+    $this->addPropertyConditions($select_query, $entity_type, $base_table);
+
+    // Process the six possible entity condition.
     // The id field is always present in entity keys.
-    $sql_field = $entity_info['entity keys']['id'];
     $id_map['entity_id'] = $sql_field;
     $select_query->addField($base_table, $sql_field, 'entity_id');
     if (isset($this->entityConditions['entity_id'])) {
-      $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['entity_id']);
+      $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions['entity_id']);
     }
 
     // If there is a revision key defined, use it.
@@ -824,7 +865,7 @@ class EntityFieldQuery {
       $sql_field = $entity_info['entity keys']['revision'];
       $select_query->addField($base_table, $sql_field, 'revision_id');
       if (isset($this->entityConditions['revision_id'])) {
-        $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['revision_id']);
+        $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions['revision_id']);
       }
     }
     else {
@@ -835,9 +876,9 @@ class EntityFieldQuery {
 
     // Handle bundles.
     if (!empty($entity_info['entity keys']['bundle'])) {
+      $base_table_schema = drupal_get_schema($base_table);
       $sql_field = $entity_info['entity keys']['bundle'];
       $having = FALSE;
-
       if (!empty($base_table_schema['fields'][$sql_field])) {
         $select_query->addField($base_table, $sql_field, 'bundle');
       }
@@ -847,10 +888,12 @@ class EntityFieldQuery {
       $select_query->addExpression(':bundle', 'bundle', array(':bundle' => $entity_type));
       $having = TRUE;
     }
+
     $id_map['bundle'] = $sql_field;
+
     if (isset($this->entityConditions['bundle'])) {
       if (!empty($entity_info['entity keys']['bundle'])) {
-        $this->addCondition($select_query, $base_table . '.' . $sql_field, $this->entityConditions['bundle'], $having);
+        $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions['bundle'], $having);
       }
       else {
         // This entity has no bundle, so invalidate the query.
@@ -858,6 +901,15 @@ class EntityFieldQuery {
       }
     }
 
+    foreach (array('uuid', 'langcode') as $key) {
+      if (isset($this->entityConditions[$key])) {
+        $sql_field = !empty($entity_info['entity keys'][$key]) ? $entity_info['entity keys'][$key] : $key;
+        if (isset($base_table_schema[$sql_field])) {
+          $this->addCondition($select_query, "$base_table.$sql_field", $this->entityConditions[$key]);
+        }
+      }
+    }
+
     // Order the query.
     foreach ($this->order as $order) {
       if ($order['type'] == 'entity') {
@@ -868,7 +920,7 @@ class EntityFieldQuery {
         $select_query->orderBy($id_map[$key], $order['direction']);
       }
       elseif ($order['type'] == 'property') {
-        $select_query->orderBy($base_table . '.' . $order['specifier'], $order['direction']);
+        $this->addPropertyOrderBy($select_query, $entity_type, $order);
       }
     }
 
@@ -961,4 +1013,114 @@ class EntityFieldQuery {
     }
   }
 
+  /**
+   * Adds property conditions to a select query performing the needed joins.
+   *
+   * @param SelectQuery $select_query
+   *   The SelectQuery the conditions should be applied to.
+   * @param $entity_type
+   *   The entity type the query applies to.
+   * @param $base_table
+   *   The name of the base table to be used for joins.
+   * @param $base_id_key
+   *   The primary id column name to use to join on the base table.
+   */
+  public function addPropertyConditions(Select $select_query, $entity_type, $base_table, $base_id_key = NULL) {
+    $entity_info = entity_get_info($entity_type);
+    $entity_base_table = $entity_info['base table'];
+    list($data_table, $data_table_schema) = $this->getPropertyDataSchema($entity_type);
+
+    // If a data table is defined we need to join it and make sure that only one
+    // record per entity is returned.
+    if (!empty($data_table)) {
+      $this->joinPropertyData($select_query, $entity_type, $base_table, $base_id_key);
+    }
+
+    foreach ($this->propertyConditions as $property_condition) {
+      $column = $property_condition['column'];
+      // @todo Property conditions should always apply to the data table (if
+      // available), however UUIDs are used in load conditions and thus treated
+      // as properties, instead of being set as entity conditions. Remove this
+      // once we can reliably distinguish between properties and metadata living
+      // on the base table.
+      $table = !empty($data_table_schema['fields'][$column]) ? $data_table  . '_' . $property_condition['langcode_group'] : $entity_base_table;
+      $this->addCondition($select_query, "$table.$column", $property_condition);
+    }
+  }
+
+  /**
+   * Adds a property order by to the given select query.
+   *
+   * @param SelectQuery $select_query
+   *   The SelectQuery the conditions should be applied to.
+   * @param $entity_type
+   *   The entity type the query applies to.
+   * @param array $order
+   *   An order array as defined in EntityFieldQuery::propertyOrderBy().
+   */
+  public function addPropertyOrderBy(Select $select_query, $entity_type, array $order) {
+    $entity_info = entity_get_info($entity_type);
+    list($data_table, $data_table_schema) = $this->getPropertyDataSchema($entity_type);
+    $specifier = $order['specifier'];
+    $table = !empty($data_table_schema['fields'][$specifier]) ? $data_table  . '_' . $order['langcode_group'] : $entity_info['base table'];
+    $select_query->orderBy("$table.$specifier", $order['direction']);
+  }
+
+  /**
+   * Returns the data table schema for the given entity type.
+   *
+   * @param $entity_type
+   *   The entity type the query applies to.
+   *
+   * @return array
+   *   An array containing the table data name (or FALSE if none is defined) and
+   *   its schema.
+   */
+  protected function getPropertyDataSchema($entity_type) {
+    $entity_info = entity_get_info($entity_type);
+    if (!empty($entity_info['data table'])) {
+      $data_table = $entity_info['data table'];
+      $data_table_schema = drupal_get_schema($data_table);
+    }
+    else {
+      $data_table = FALSE;
+      $data_table_schema = array();
+    }
+    return array($data_table, $data_table_schema);
+  }
+
+  /**
+   * Joins the needed data tables based on the specified property conditions.
+   *
+   * @param SelectQuery $select_query
+   *   A SelectQuery containing at least one table as specified by $base_table.
+   * @param $entity_type
+   *   The entity type the query applies to.
+   * @param $base_table
+   *   The name of the base table to join on.
+   * @param $base_id_key
+   *   The primary id column name to use to join on the base table.
+   */
+  protected function joinPropertyData(Select $select_query, $entity_type, $base_table, $base_id_key = NULL) {
+    $entity_info = entity_get_info($entity_type);
+
+    // If we have no data table there are no property meta conditions to handle.
+    if (empty($entity_info['data table'])) {
+      return;
+    }
+
+    $data_table = $entity_info['data table'];
+    $id_key = $entity_info['entity keys']['id'];
+    $base_id_key = !empty($base_id_key) ? $base_id_key : $id_key;
+
+    foreach ($this->properties as $key => $property) {
+      // Every properties needs a new join on the data table.
+      $table_alias = $data_table . '_' . $key;
+      $table_aliases[$key] = $table_alias;
+      $select_query->join($data_table, $table_alias, "$table_alias.$id_key = $base_table.$base_id_key");
+    }
+
+    // Ensure we return just one value.
+    $select_query->distinct();
+  }
 }
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php
index c7f7961..f20c614 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php
@@ -9,6 +9,8 @@ namespace Drupal\entity\Tests;
 
 use Exception;
 use InvalidArgumentException;
+
+use Drupal\entity\EntityFieldQuery;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -229,5 +231,37 @@ class EntityTranslationTest extends WebTestBase {
     $this->assertEqual(count($entities), 1, 'One entity loaded by name translation and language specifying to look for translations.');
     $entities = entity_load_multiple_by_properties('entity_test', array('uid' => $properties[$langcode]['uid'], 'default_langcode' => NULL));
     $this->assertEqual(count($entities), 2, 'Two entities loaded by uid without caring about property translatability.');
+
+    // Test property conditions and orders with multiple languages in the same
+    // query.
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', 'entity_test');
+    $query->propertyCondition('uid', $properties[$default_langcode]['uid'], NULL, 'original');
+    $query->propertyCondition('name', $properties[$default_langcode]['name'], NULL, 'original');
+    $query->propertyLanguageCondition($default_langcode, NULL, 'original');
+    $query->propertyCondition('name', $properties[$langcode]['name'], NULL, 'translation');
+    $query->propertyLanguageCondition($langcode, NULL, 'translation');
+    $query->propertyOrderBy('name', 'ASC', 'original');
+    $result = $query->execute();
+    $this->assertEqual(count($result), 1, 'One entity loaded by name and uid using different language meta conditions.');
+
+    // Test mixed property and field conditions.
+    $entity = entity_load('entity_test', key($result['entity_test']), TRUE);
+    $field_value = $this->randomString();
+    $entity->set($this->field_name, array(array('value' => $field_value)), $langcode);
+    $entity->save();
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', 'entity_test');
+    $query->propertyCondition('uid', $properties[$default_langcode]['uid'], NULL, 'original');
+    $query->propertyCondition('name', $properties[$default_langcode]['name'], NULL, 'original');
+    $query->propertyLanguageCondition($default_langcode, NULL, 'original');
+    $query->propertyCondition('name', $properties[$langcode]['name'], NULL, 'translation');
+    $query->propertyLanguageCondition($langcode, NULL, 'translation');
+    $query->fieldCondition($this->field_name, 'value', $field_value, NULL, NULL, 'translation');
+    $query->fieldLanguageCondition($this->field_name, $langcode, NULL, NULL, 'translation');
+    $query->propertyOrderBy('name', 'ASC', 'original');
+    $result = $query->execute();
+    $result = $query->execute();
+    $this->assertEqual(count($result), 1, 'One entity loaded by name, uid and field value using different language meta conditions.');
   }
 }
diff --git a/core/modules/entity/tests/modules/entity_test/entity_test.module b/core/modules/entity/tests/modules/entity_test/entity_test.module
index 02ec108..0980c85 100644
--- a/core/modules/entity/tests/modules/entity_test/entity_test.module
+++ b/core/modules/entity/tests/modules/entity_test/entity_test.module
@@ -14,6 +14,7 @@ function entity_test_entity_info() {
     'entity class' => 'Drupal\entity_test\EntityTest',
     'controller class' => 'Drupal\entity_test\EntityTestStorageController',
     'base table' => 'entity_test',
+    'data table' => 'entity_test_property_data',
     'fieldable' => TRUE,
     'entity keys' => array(
       'id' => 'id',
diff --git a/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
index 4fac83c..21228b2 100644
--- a/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
+++ b/core/modules/entity/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
@@ -9,8 +9,9 @@ namespace Drupal\entity_test;
 
 use PDO;
 
-use Drupal\entity\StorableInterface;
 use Drupal\entity\DatabaseStorageController;
+use Drupal\entity\EntityFieldQuery;
+use Drupal\entity\StorableInterface;
 
 /**
  * Defines the controller class for the test entity.
@@ -21,40 +22,24 @@ use Drupal\entity\DatabaseStorageController;
 class EntityTestStorageController extends DatabaseStorageController {
 
   /**
-   * Overrides Drupal\entity\DatabaseStorageController::loadByProperties().
+   * Overrides Drupal\entity\DatabaseStorageController::buildPropertyQuery().
    */
-  public function loadByProperties(array $values) {
-    $query = db_select($this->entityInfo['base table'], 'base');
-    $query->addTag($this->entityType . '_load_multiple');
-    if ($values) {
-      // Conditions need to be applied the property data table.
-      $query->addJoin('inner', 'entity_test_property_data', 'data', "base.{$this->idKey} = data.{$this->idKey}");
-      $query->distinct(TRUE);
-
-      // @todo We should not be using a condition to specify whether conditions
-      // apply to the default language or not. We need to move this to a
-      // separate parameter during the following API refactoring.
-      // Default to the original entity language if not explicitly specified
-      // otherwise.
-      if (!array_key_exists('default_langcode', $values)) {
-        $values['default_langcode'] = 1;
-      }
-      // If the 'default_langcode' flag is esplicitly not set, we do not care
-      // whether the queried values are in the original entity language or not.
-      elseif ($values['default_langcode'] === NULL) {
-        unset($values['default_langcode']);
-      }
-
-      $data_schema = drupal_get_schema('entity_test_property_data');
-      $query->addField('data', $this->idKey);
-      foreach ($values as $field => $value) {
-        // Check on which table the condition needs to be added.
-        $table = isset($data_schema['fields'][$field]) ? 'data' : 'base';
-        $query->condition($table . '.' . $field, $value);
-      }
+  protected function buildPropertyQuery(EntityFieldQuery $entity_query, array $values) {
+    // @todo We should not be using a condition to specify whether conditions
+    // apply to the default language or not. We need to move this to a
+    // separate parameter during the following API refactoring.
+    // Default to the original entity language if not explicitly specified
+    // otherwise.
+    if (!array_key_exists('default_langcode', $values)) {
+      $values['default_langcode'] = 1;
     }
-    $ids = $query->execute()->fetchCol();
-    return $ids ? $this->load($ids) : array();
+    // If the 'default_langcode' flag is esplicitly not set, we do not care
+    // whether the queried values are in the original entity language or not.
+    elseif ($values['default_langcode'] === NULL) {
+      unset($values['default_langcode']);
+    }
+
+    parent::buildPropertyQuery($entity_query, $values);
   }
 
   /**
diff --git a/core/modules/field/modules/field_sql_storage/field_sql_storage.module b/core/modules/field/modules/field_sql_storage/field_sql_storage.module
index 69e8bda..bda5bb7 100644
--- a/core/modules/field/modules/field_sql_storage/field_sql_storage.module
+++ b/core/modules/field/modules/field_sql_storage/field_sql_storage.module
@@ -550,6 +550,8 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
     }
   }
 
+  $entity_type = FALSE;
+  $entity_base_table = FALSE;
   if ($query->propertyConditions || $has_property_order) {
     if (empty($query->entityConditions['entity_type']['value'])) {
       throw new EntityFieldQueryException('Property conditions and orders must have an entity type defined.');
@@ -557,12 +559,37 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
     $entity_type = $query->entityConditions['entity_type']['value'];
     $entity_base_table = _field_sql_storage_query_join_entity($select_query, $entity_type, $field_base_table);
     $query->entityConditions['entity_type']['operator'] = '=';
-    foreach ($query->propertyConditions as $property_condition) {
-      $query->addCondition($select_query, "$entity_base_table." . $property_condition['column'], $property_condition);
-    }
+    $query->addPropertyConditions($select_query, $entity_type, $field_base_table, 'entity_id');
   }
+
+  // The entity base keys require joining the entity base table.
+  $entity_base_keys = array('langcode', 'uuid');
   foreach ($query->entityConditions as $key => $condition) {
-    $query->addCondition($select_query, "$field_base_table.$key", $condition);
+    $table = FALSE;
+    if (!in_array($key, $entity_base_keys)) {
+      $table = $field_base_table;
+    }
+    else {
+      // Join only if we did not already before.
+      if (empty($entity_base_table)) {
+        if (empty($query->entityConditions['entity_type']['value'])) {
+          throw new EntityFieldQueryException('Property conditions and orders must have an entity type defined.');
+        }
+        $entity_type = $query->entityConditions['entity_type']['value'];
+        $entity_base_table = _field_sql_storage_query_join_entity($select_query, $entity_type, $field_base_table);
+      }
+      if (empty($entity_schema)) {
+        $entity_schema = drupal_get_schema($entity_base_table);
+      }
+      if (!empty($entity_schema['fields'][$key])) {
+        $table = $entity_base_table;
+      }
+    }
+    // Apply the condition only if we have a valid table: entity conditions may
+    // refer to non existing columns.
+    if ($table) {
+      $query->addCondition($select_query, "$table.$key", $condition);
+    }
   }
 
   // Order the query.
@@ -579,7 +606,7 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) {
       $select_query->orderBy($sql_field, $order['direction']);
     }
     elseif ($order['type'] == 'property') {
-      $select_query->orderBy("$entity_base_table." . $order['specifier'], $order['direction']);
+      $query->addPropertyOrderBy($select_query, $entity_type, $order);
     }
   }
 
