Index: src/wp-includes/category.php
===================================================================
--- src/wp-includes/category.php	(revision 34035)
+++ src/wp-includes/category.php	(working copy)
@@ -322,6 +322,10 @@
  * @param array|object $category Category Row object or array
  */
 function _make_cat_compat( &$category ) {
+	// fix for "Indirect modification of overloaded property" notice
+	if ( $category instanceof WP_Term )
+		$category = (object) $category->to_array();
+
 	if ( is_object( $category ) && ! is_wp_error( $category ) ) {
 		$category->cat_ID = &$category->term_id;
 		$category->category_count = &$category->count;
Index: src/wp-includes/class-wp-term.php
===================================================================
--- src/wp-includes/class-wp-term.php	(revision 0)
+++ src/wp-includes/class-wp-term.php	(working copy)
@@ -0,0 +1,214 @@
+<?php
+/**
+ * WordPress Term class.
+ *
+ * @since 4.4.0
+ * @package WordPress
+ * @subpackage Taxonomy
+ *
+ */
+final class WP_Term {
+
+	/**
+	 * Term ID.
+	 *
+	 * @var int
+	 */
+	public $term_id;
+
+	/**
+	 * The term's name.
+	 *
+	 * @var string
+	 */
+	public $name = '';
+
+	/**
+	 * The term's slug.
+	 *
+	 * @var string
+	 */
+	public $slug = '';
+
+	public $term_group = '';
+
+	/**
+	 * Term Taxonomy ID.
+	 *
+	 * @var int
+	 */
+	public $term_taxonomy_id = 0;
+
+	/**
+	 * The term's taxonomy name.
+	 *
+	 * @var string
+	 */
+	public $taxonomy = '';
+
+	/**
+	 * The term's description.
+	 *
+	 * @var string
+	 */
+	public $description = '';
+
+	/**
+	 * ID of a term's parent term.
+	 *
+	 * @var int
+	 */
+	public $parent = 0;
+
+	/**
+	 * Cached object count for this term.
+	 *
+	 * @var int
+	 */
+	public $count = 0;
+
+	/**
+	 * Stores the term object's sanitization level.
+	 *
+	 * Does not correspond to a DB field.
+	 *
+	 * @var string
+	 */
+	public $filter;
+
+	/**
+	 * Retrieve WP_Term instance.
+	 *
+	 * @static
+	 * @access public
+	 *
+	 * @global wpdb $wpdb
+	 *
+	 * @param int $term_id Term ID.
+	 * @return WP_Term|false Term object, false otherwise.
+	 */
+	public static function get_instance( $term_id, $taxonomy ) {
+		global $wpdb;
+
+		$term_id = (int) $term_id;
+		if ( ! $term_id )
+			return false;
+
+		$_term = wp_cache_get( $term_id, $taxonomy );
+
+		if ( ! $_term ) {
+			$_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term_id) );
+			if ( ! $_term )
+				return false;
+
+			$_term = sanitize_term( $_term, $taxonomy, 'raw' );
+			wp_cache_add( $term_id, $_term, $taxonomy );
+		} elseif ( empty( $_term->filter ) ) {
+			$_term = sanitize_term( $_term, $taxonomy, 'raw' );
+		}
+
+		return new WP_Term( $_term );
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param WP_Term|object $term Term object.
+	 */
+	public function __construct( $term ) {
+		foreach ( get_object_vars( $term ) as $key => $value )
+			$this->$key = $value;
+	}
+
+	/**
+	 * Isset-er.
+	 *
+	 * @param string $key Property to check if set.
+	 * @return bool
+	 */
+	public function __isset( $key ) {
+		if ( 'ancestors' == $key )
+			return true;
+
+		if ( 'children' == $key )
+			return true;
+
+		if ( 'link' == $key )
+			return true;
+
+		if ( 'objects' == $key )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Getter.
+	 *
+	 * @param string $key Key to get.
+	 * @return mixed
+	 */
+	public function __get( $key ) {
+		if ( 'ancestors' == $key ) {
+			if ( empty( $this->parent ) || $this->parent == $this->term_id )
+				return array();
+
+			$ancestors = array();
+
+			$id = $ancestors[] = $this->parent;
+
+			while ( $ancestor = get_term( $id, $this->taxonomy ) ) {
+				// Loop detection: If the ancestor has been seen before, break.
+				if ( empty( $ancestor->parent ) || ( $ancestor->parent == $this->term_id ) || in_array( $ancestor->parent, $ancestors ) )
+					break;
+
+				$id = $ancestors[] = $ancestor->parent;
+			}
+
+			return $ancestors;
+		}
+
+		if ( 'children' == $key )
+			return get_term_children( $this->term_id, $this->taxonomy );
+
+		if ( 'link' == $key )
+			return get_term_link( $this->term_id, $this->taxonomy );
+
+		if ( 'objects' == $key )
+			return get_objects_in_term( $this->term_id, $this->taxonomy );
+
+		return false;
+	}
+
+	/**
+	 * {@Missing Summary}
+	 *
+	 * @param string $filter Filter.
+	 * @return self|array|bool|object|WP_Term
+	 */
+	public function filter( $filter ) {
+		if ( $this->filter == $filter )
+			return $this;
+
+		if ( $filter == 'raw' )
+			return self::get_instance( $this->term_id, $this->taxonomy );
+
+		return sanitize_term( $this, $this->taxonomy, $filter );
+	}
+
+	/**
+	 * Convert object to array.
+	 *
+	 * @return array Object as array.
+	 */
+	public function to_array() {
+		$term = get_object_vars( $this );
+
+		foreach ( array( 'ancestors', 'children', 'link', 'objects' ) as $key ) {
+			if ( $this->__isset( $key ) )
+				$term[ $key ] = $this->__get( $key );
+		}
+
+		return $term;
+	}
+}
Index: src/wp-includes/taxonomy-functions.php
===================================================================
--- src/wp-includes/taxonomy-functions.php	(revision 34035)
+++ src/wp-includes/taxonomy-functions.php	(working copy)
@@ -685,16 +685,14 @@
  * @global wpdb $wpdb WordPress database abstraction object.
  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
  *
- * @param int|object $term     If integer, will get from database. If object will apply filters and return $term.
- * @param string     $taxonomy Taxonomy name that $term is part of.
- * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
- * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
- * @return object|array|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
- * exist then WP_Error will be returned.
+ * @param int|WP_Term $term     If integer, will get from database. If object will apply filters and return $term.
+ * @param string     	$taxonomy Taxonomy name that $term is part of.
+ * @param string     	$output   Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string     	$filter   Optional, default is raw or no WordPress defined filter will applied.
+ * @return WP_Term|array|null|WP_Error Type corresponding to $output on success or null on failure. When $output is OBJECT,
+ *                                     a `WP_Term` instance is returned. If taxonomy does not exist then WP_Error will be returned.
  */
 function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
-	global $wpdb;
-
 	if ( empty( $term ) ) {
 		return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
 	}
@@ -703,22 +701,24 @@
 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
 	}
 
-	if ( is_object($term) && empty($term->filter) ) {
-		wp_cache_add( $term->term_id, $term, $taxonomy );
+	if ( $term instanceof WP_Term ) {
 		$_term = $term;
+	} elseif ( is_object( $term ) ) {
+		if ( empty( $term->filter ) ) {
+			$_term = sanitize_term( $term, $taxonomy, 'raw' );
+			$_term = new WP_Term( $_term );
+		} elseif ( 'raw' == $term->filter ) {
+			$_term = new WP_Term( $term );
+		} else {
+			$_term = WP_Term::get_instance( $term->term_id, $taxonomy );
+		}
 	} else {
-		if ( is_object($term) )
-			$term = $term->term_id;
-		if ( !$term = (int) $term )
-			return null;
-		if ( ! $_term = wp_cache_get( $term, $taxonomy ) ) {
-			$_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) );
-			if ( ! $_term )
-				return null;
-			wp_cache_add( $term, $_term, $taxonomy );
-		}
+		$_term = WP_Term::get_instance( $term, $taxonomy );
 	}
 
+	if ( ! $_term )
+		return null;
+
 	/**
 	 * Filter a term.
 	 *
@@ -743,17 +743,12 @@
 	$_term = apply_filters( "get_$taxonomy", $_term, $taxonomy );
 	$_term = sanitize_term($_term, $taxonomy, $filter);
 
-	if ( $output == OBJECT ) {
-		return $_term;
-	} elseif ( $output == ARRAY_A ) {
-		$__term = get_object_vars($_term);
-		return $__term;
-	} elseif ( $output == ARRAY_N ) {
-		$__term = array_values(get_object_vars($_term));
-		return $__term;
-	} else {
-		return $_term;
-	}
+	if ( $output == ARRAY_A )
+		return $_term->to_array();
+	elseif ( $output == ARRAY_N )
+		return array_values( $_term->to_array() );
+
+	return $_term;
 }
 
 /**
@@ -780,7 +775,7 @@
  * @param string     $taxonomy Taxonomy Name
  * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
  * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
- * @return object|array|null|WP_Error|false Term Row from database.
+ * @return WP_Term|array|null|WP_Error|false Instance of WP_Term.
  *                                          Will return false if $taxonomy does not exist or $term was not found.
  */
 function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
@@ -814,23 +809,7 @@
 
 	wp_cache_add( $term->term_id, $term, $taxonomy );
 
-	/** This filter is documented in wp-includes/taxonomy-functions.php */
-	$term = apply_filters( 'get_term', $term, $taxonomy );
-
-	/** This filter is documented in wp-includes/taxonomy-functions.php */
-	$term = apply_filters( "get_$taxonomy", $term, $taxonomy );
-
-	$term = sanitize_term($term, $taxonomy, $filter);
-
-	if ( $output == OBJECT ) {
-		return $term;
-	} elseif ( $output == ARRAY_A ) {
-		return get_object_vars($term);
-	} elseif ( $output == ARRAY_N ) {
-		return array_values(get_object_vars($term));
-	} else {
-		return $term;
-	}
+	return get_term( $term, $taxonomy, $output, $filter );
 }
 
 /**
@@ -1003,7 +982,7 @@
  *     @type string       $cache_domain      Unique cache key to be produced when this query is stored in an
  *                                           object cache. Default is 'core'.
  * }
- * @return array|int|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies
+ * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies
  *                        do not exist.
  */
 function get_terms( $taxonomies, $args = '' ) {
@@ -1427,6 +1406,10 @@
 		foreach ( $terms as $term ) {
 			$_terms[ $term->term_id ] = $term->slug;
 		}
+	} else {
+		foreach ( $terms as $term ) {
+			$_terms[ $term->term_id ] = get_term( $term, $term->taxonomy );
+		}
 	}
 
 	if ( ! empty( $_terms ) ) {
Index: src/wp-includes/taxonomy.php
===================================================================
--- src/wp-includes/taxonomy.php	(revision 34035)
+++ src/wp-includes/taxonomy.php	(working copy)
@@ -9,4 +9,5 @@
  */
 
 require_once( ABSPATH . WPINC . '/taxonomy-functions.php' );
+require_once( ABSPATH . WPINC . '/class-wp-term.php' );
 require_once( ABSPATH . WPINC . '/class-wp-tax-query.php' );
Index: tests/phpunit/tests/xmlrpc/wp/getTerm.php
===================================================================
--- tests/phpunit/tests/xmlrpc/wp/getTerm.php	(revision 34035)
+++ tests/phpunit/tests/xmlrpc/wp/getTerm.php	(working copy)
@@ -95,4 +95,32 @@
 		$this->assertEquals( 'category', $result['taxonomy'] );
 		$this->assertEquals( $term['description'], $result['description'] );
 	}
+
+	/**
+	 * @ticket 14162
+	 */
+	function test_get_term_object() {
+		$this->make_user_by_role( 'editor' );
+
+		$term = get_term( $this->term['term_id'], 'category', ARRAY_A );
+
+		$this->assertNotInstanceOf( 'IXR_Error', $term );
+		$this->assertInstanceOf( 'WP_Term', $term );
+
+		// Check DataTypes
+		$this->assertInternalType( 'string', $term->name );
+		$this->assertInternalType( 'string',$term->slug );
+		$this->assertInternalType( 'string', $term->taxonomy );
+		$this->assertInternalType( 'string', $term->description );
+		$this->assertInternalType( 'int', $term->count );
+
+		// We expect all ID's to be strings not integers so we don't return something larger than an XMLRPC integer can describe.
+		$this->assertStringMatchesFormat( '%d', $term->term_id );
+		$this->assertStringMatchesFormat( '%d', $term->term_group );
+		$this->assertStringMatchesFormat( '%d', $term->term_taxonomy_id );
+		$this->assertStringMatchesFormat( '%d', $term->parent );
+
+		// Check Data
+		$this->assertEquals( 0, $term->count );
+	}
 }
