Index: src/wp-includes/meta.php
===================================================================
--- src/wp-includes/meta.php	(revision 31290)
+++ src/wp-includes/meta.php	(working copy)
@@ -934,6 +934,14 @@
 	protected $table_aliases = array();
 
 	/**
+	 * A flat list of clauses, keyed by table aliases.
+	 *
+	 * @since 4.2.0
+	 * @var array
+	 */
+	protected $clauses = array();
+
+	/**
 	 * Constructor.
 	 *
 	 * @since 3.2.0
@@ -1374,6 +1382,14 @@
 		// Save the alias to this clause, for future siblings to find.
 		$clause['alias'] = $alias;
 
+		// Determine the data type.
+		$meta_type = $this->get_cast_for_type( isset( $clause['type'] ) ? $clause['type'] : '' );
+		$clause['cast'] = $meta_type;
+
+		// Store the clause in our flat array.
+		$clause_name = isset( $clause['name'] ) ? $clause['name'] : $clause['alias'];
+		$this->clauses[ $clause_name ] =& $clause;
+
 		// Next, build the WHERE clause.
 
 		// meta_key.
@@ -1388,7 +1404,6 @@
 		// meta_value.
 		if ( array_key_exists( 'value', $clause ) ) {
 			$meta_value = $clause['value'];
-			$meta_type = $this->get_cast_for_type( isset( $clause['type'] ) ? $clause['type'] : '' );
 
 			if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
 				if ( ! is_array( $meta_value ) ) {
@@ -1450,6 +1465,10 @@
 		return $sql_chunks;
 	}
 
+	public function get_clauses() {
+		return $this->clauses;
+	}
+
 	/**
 	 * Identify an existing table alias that is compatible with the current
 	 * query clause.
Index: src/wp-includes/query.php
===================================================================
--- src/wp-includes/query.php	(revision 31290)
+++ src/wp-includes/query.php	(working copy)
@@ -2233,8 +2233,9 @@
 
 		$primary_meta_key = '';
 		$primary_meta_query = false;
-		if ( ! empty( $this->meta_query->queries ) ) {
-			$primary_meta_query = reset( $this->meta_query->queries );
+		$meta_clauses = $this->meta_query->get_clauses();
+		if ( ! empty( $meta_clauses ) ) {
+			$primary_meta_query = reset( $meta_clauses );
 
 			if ( ! empty( $primary_meta_query['key'] ) ) {
 				$primary_meta_key = $primary_meta_query['key'];
@@ -2243,6 +2244,7 @@
 
 			$allowed_keys[] = 'meta_value';
 			$allowed_keys[] = 'meta_value_num';
+			$allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
 		}
 
 		if ( ! in_array( $orderby, $allowed_keys ) ) {
@@ -2260,29 +2262,33 @@
 			case 'ID':
 			case 'menu_order':
 			case 'comment_count':
-				$orderby = "$wpdb->posts.{$orderby}";
+				$orderby_clause = "$wpdb->posts.{$orderby}";
 				break;
 			case 'rand':
-				$orderby = 'RAND()';
+				$orderby_clause = 'RAND()';
 				break;
 			case $primary_meta_key:
 			case 'meta_value':
 				if ( ! empty( $primary_meta_query['type'] ) ) {
-					$sql_type = $this->meta_query->get_cast_for_type( $primary_meta_query['type'] );
-					$orderby = "CAST($wpdb->postmeta.meta_value AS {$sql_type})";
+					$orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
 				} else {
-					$orderby = "$wpdb->postmeta.meta_value";
+					$orderby_clause = "{$primary_meta_query['alias']}.meta_value";
 				}
 				break;
 			case 'meta_value_num':
-				$orderby = "$wpdb->postmeta.meta_value+0";
+				$orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
 				break;
 			default:
-				$orderby = "$wpdb->posts.post_" . $orderby;
+				if( array_key_exists( $orderby, $meta_clauses ) ){
+					$meta_clause = $meta_clauses[ $orderby ];
+					$orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
+				} else {
+					$orderby_clause = "$wpdb->posts.post_" . $orderby;
+				}
 				break;
 		}
 
-		return $orderby;
+		return apply_filters( 'parse_orderby', $orderby_clause, $orderby );
 	}
 
 	/**
@@ -2813,6 +2819,12 @@
 
 		$where .= $search . $whichauthor . $whichmimetype;
 
+		if ( ! empty( $this->meta_query->queries ) ) {
+			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
+			$join   .= $clauses['join'];
+			$where  .= $clauses['where'];
+		}
+
 		$rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
 		if ( ! isset( $q['order'] ) ) {
 			$q['order'] = $rand ? '' : 'DESC';
@@ -3030,12 +3042,6 @@
 			$where .= ')';
 		}
 
-		if ( !empty( $this->meta_query->queries ) ) {
-			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
-			$join .= $clauses['join'];
-			$where .= $clauses['where'];
-		}
-
 		/*
 		 * Apply filters on where and join prior to paging so that any
 		 * manipulations to them are reflected in the paging by day queries.
