diff --git a/docs/InnerHits/Nested.md b/docs/InnerHits/Nested.md
new file mode 100644
index 0000000000000000000000000000000000000000..76b6990436d21e561c96ae695bb5aa092ed76892
--- /dev/null
+++ b/docs/InnerHits/Nested.md
@@ -0,0 +1,111 @@
+# Nested Inner Hits
+
+> More info about inner hits is in the [official elasticsearch docs][1]
+
+The nested inner_hits can be used to include nested inner objects as inner hits to a search hit.
+The actual matches in the different scopes that caused a document to be returned is hidden.
+In many cases, it’s very useful to know which inner nested objects caused certain information to be returned.
+
+## Simple example
+
+```JSON
+{
+    "query" : {
+        "nested" : {
+            "path" : "comments",
+            "query" : {
+                "match" : {"comments.message" : "[actual query]"}
+            }
+        }
+    },
+    "inner_hits" : {
+        "comment" : {
+            "path" : {
+                "comments" : {
+                    "query" : {
+                        "match" : {"comments.message" : "[different query]"}
+                    }
+                }
+            }
+        }
+    }
+}
+```
+
+And now the query via DSL:
+
+```php
+$matchQuery = new MatchQuery('comments.message', '[different query]');
+$nestedQuery = new NestedQuery('comments', $matchQuery);
+$innerHit = new NestedInnerHit('comment', 'comments', $matchQuery);
+
+$search = new Search();
+$search->addQuery(new MatchQuery('comments.message', '[actual query]'));
+$search->addInnerHit($innerHit);
+$search->toArray();
+```
+
+In the example above `comment` is the name of the inner hit, `comments` is the path
+to the nested field and `$matchQuery` is the actual query that will be executed.
+
+## Nesting inner hits
+
+It is possible to nest inner hits in order to reach deeper levels of nested objects.
+Here is an example of nesting inner hits:
+
+```JSON
+{
+  "inner_hits": {
+    "cars": {
+      "path": {
+        "cars": {
+          "query": {
+            "nested": {
+              "path": "cars.manufacturers",
+              "query": {
+                "match": {
+                  "cars.manufacturers.country": {
+                    "query": "Japan"
+                  }
+                }
+              }
+            }
+          },
+          "inner_hits": {
+            "manufacturers": {
+              "path": {
+                "cars.manufacturers": {
+                  "query": {
+                    "match": {
+                      "cars.manufacturers.country": {
+                        "query": "Japan"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+```
+
+And now the query via DSL:
+
+```php
+
+$matchQuery = new MatchQuery('cars.manufacturers.country', 'Japan');
+$nestedQuery = new NestedQuery('cars.manufacturers', $matchQuery);
+$innerHitNested = new NestedInnerHit('manufacturers', 'cars.manufacturers', $matchQuery);
+$innerHit = new NestedInnerHit('cars', 'cars', $nestedQuery);
+$innerHit->addInnerHit($innerHitNested);
+
+$search = new Search();
+$search->addInnerHit($innerHit);
+$search->toArray();
+
+```
+[1]: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-inner-hits.html
\ No newline at end of file
diff --git a/src/InnerHit/NestedInnerHit.php b/src/InnerHit/NestedInnerHit.php
new file mode 100644
index 0000000000000000000000000000000000000000..73dc853b116cf937c377ee08ead4c0da4b558aac
--- /dev/null
+++ b/src/InnerHit/NestedInnerHit.php
@@ -0,0 +1,197 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\InnerHit;
+
+use ONGR\ElasticsearchDSL\BuilderBag;
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\NameAwareTrait;
+use ONGR\ElasticsearchDSL\ParametersTrait;
+
+/**
+ * Represents Elasticsearch top level nested inner hits.
+ *
+ * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-inner-hits.html
+ */
+class NestedInnerHit implements BuilderInterface
+{
+    use ParametersTrait;
+    use NameAwareTrait;
+
+    /**
+     * @var string
+     */
+    private $path;
+
+    /**
+     * @var BuilderInterface
+     */
+    private $query;
+
+    /**
+     * @var BuilderBag
+     */
+    private $innerHits;
+
+    /**
+     * Inner hits container init.
+     *
+     * @param string           $name
+     * @param string           $path
+     * @param BuilderInterface $query
+     */
+    public function __construct($name, $path, BuilderInterface $query)
+    {
+        $this->setName($name);
+        $this->setPath($path);
+        $this->setQuery($query);
+    }
+
+    /**
+     * @return string
+     */
+    public function getPath()
+    {
+        return $this->path;
+    }
+
+    /**
+     * @param string $path
+     */
+    public function setPath($path)
+    {
+        $this->path = $path;
+    }
+
+    /**
+     * @return BuilderInterface
+     */
+    public function getQuery()
+    {
+        return $this->query;
+    }
+
+    /**
+     * @param BuilderInterface $query
+     */
+    public function setQuery(BuilderInterface $query)
+    {
+        $this->query = $query;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getType()
+    {
+        return 'nested';
+    }
+
+    /**
+     * Adds a sub-innerHit.
+     *
+     * @param NestedInnerHit $innerHit
+     */
+    public function addInnerHit(NestedInnerHit $innerHit)
+    {
+        if (!$this->innerHits) {
+            $this->innerHits = new BuilderBag();
+        }
+
+        $this->innerHits->add($innerHit);
+    }
+
+    /**
+     * Returns all sub inner hits.
+     *
+     * @return BuilderInterface[]
+     */
+    public function getInnerHits()
+    {
+        if ($this->innerHits) {
+            return $this->innerHits->all();
+        } else {
+            return [];
+        }
+    }
+
+    /**
+     * Returns sub inner hit.
+     * @param string $name inner hit name to return.
+     *
+     * @return NestedInnerHit|null
+     */
+    public function getInnerHit($name)
+    {
+        if ($this->innerHits && $this->innerHits->has($name)) {
+            return $this->innerHits->get($name);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toArray()
+    {
+        $out = array_filter(
+            [
+                'query' => $this->getQuery()->toArray(),
+                'inner_hits' => $this->collectNestedInnerHits(),
+            ]
+        );
+
+        $out = [
+            $this->getPathType() => [
+                $this->getPath() => $this->processArray($out),
+            ],
+        ];
+
+        return $out;
+    }
+
+    /**
+     * Returns 'path' for neted and 'type' for parent inner hits
+     *
+     * @return null|string
+     */
+    private function getPathType()
+    {
+        switch ($this->getType()) {
+            case 'nested':
+                $type = 'path';
+                break;
+            case 'parent':
+                $type = 'type';
+                break;
+            default:
+                $type = null;
+        }
+        return $type;
+    }
+
+    /**
+     * Process all nested inner hits.
+     *
+     * @return array
+     */
+    private function collectNestedInnerHits()
+    {
+        $result = [];
+        /** @var NestedInnerHit $innerHit */
+        foreach ($this->getInnerHits() as $innerHit) {
+            $result[$innerHit->getName()] = $innerHit->toArray();
+        }
+
+        return $result;
+    }
+}
diff --git a/src/Search.php b/src/Search.php
index 9760d652aa626f4ff07cc14838b6cb973de5a43a..e9af022d142f1f64695f0e07a6bc4e36a3dfd602 100644
--- a/src/Search.php
+++ b/src/Search.php
@@ -13,11 +13,13 @@ namespace ONGR\ElasticsearchDSL;
 
 use ONGR\ElasticsearchDSL\Aggregation\AbstractAggregation;
 use ONGR\ElasticsearchDSL\Highlight\Highlight;
+use ONGR\ElasticsearchDSL\InnerHit\NestedInnerHit;
 use ONGR\ElasticsearchDSL\Query\BoolQuery;
 use ONGR\ElasticsearchDSL\SearchEndpoint\AbstractSearchEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\AggregationsEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\FilterEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\HighlightEndpoint;
+use ONGR\ElasticsearchDSL\SearchEndpoint\InnerHitsEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\PostFilterEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\QueryEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\SearchEndpointFactory;
@@ -328,6 +330,30 @@ class Search
         return $this->getEndpoint(AggregationsEndpoint::NAME)->getAll();
     }
 
+    /**
+     * Adds inner hit into search.
+     *
+     * @param NestedInnerHit $innerHit
+     *
+     * @return $this
+     */
+    public function addInnerHit(NestedInnerHit $innerHit)
+    {
+        $this->getEndpoint(InnerHitsEndpoint::NAME)->add($innerHit, $innerHit->getName());
+
+        return $this;
+    }
+
+    /**
+     * Returns all inner hits.
+     *
+     * @return BuilderInterface[]
+     */
+    public function getInnerHits()
+    {
+        return $this->getEndpoint(InnerHitsEndpoint::NAME)->getAll();
+    }
+
     /**
      * Adds sort to search.
      *
diff --git a/src/SearchEndpoint/InnerHitsEndpoint.php b/src/SearchEndpoint/InnerHitsEndpoint.php
new file mode 100644
index 0000000000000000000000000000000000000000..b3d4213090960b1683198a8a0fc1078498b92980
--- /dev/null
+++ b/src/SearchEndpoint/InnerHitsEndpoint.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\InnerHit\AbstractInnerHit;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+/**
+ * Search inner hits dsl endpoint.
+ */
+class InnerHitsEndpoint extends AbstractSearchEndpoint
+{
+    /**
+     * Endpoint name
+     */
+    const NAME = 'inner_hits';
+
+    /**
+     * {@inheritdoc}
+     */
+    public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
+    {
+        $output = [];
+        if (count($this->getAll()) > 0) {
+            /** @var AbstractInnerHit $innerHit */
+            foreach ($this->getAll() as $innerHit) {
+                $output[$innerHit->getName()] = $innerHit->toArray();
+            }
+        }
+
+        return $output;
+    }
+}
diff --git a/src/SearchEndpoint/SearchEndpointFactory.php b/src/SearchEndpoint/SearchEndpointFactory.php
index 291a631479b5f94eba66a6a4f6cda191e1348622..abfcf6112fdb86db708974913a992d2e64d63296 100644
--- a/src/SearchEndpoint/SearchEndpointFactory.php
+++ b/src/SearchEndpoint/SearchEndpointFactory.php
@@ -27,6 +27,7 @@ class SearchEndpointFactory
         'highlight' => 'ONGR\ElasticsearchDSL\SearchEndpoint\HighlightEndpoint',
         'aggregations' => 'ONGR\ElasticsearchDSL\SearchEndpoint\AggregationsEndpoint',
         'suggest' => 'ONGR\ElasticsearchDSL\SearchEndpoint\SuggestEndpoint',
+        'inner_hits' => 'ONGR\ElasticsearchDSL\SearchEndpoint\InnerHitsEndpoint',
     ];
 
     /**
diff --git a/tests/InnerHit/NestedInnerHitTest.php b/tests/InnerHit/NestedInnerHitTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9cb88fcddee54176118acec853512654d92b51b8
--- /dev/null
+++ b/tests/InnerHit/NestedInnerHitTest.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace ONGR\ElasticsearchDSL\Tests\InnerHit;
+
+use ONGR\ElasticsearchDSL\InnerHit\NestedInnerHit;
+use ONGR\ElasticsearchDSL\Query\MatchQuery;
+use ONGR\ElasticsearchDSL\Query\NestedQuery;
+use ONGR\ElasticsearchDSL\Query\TermQuery;
+
+class NestedInnerHitTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Data provider for testToArray().
+     *
+     * @return array
+     */
+    public function getTestToArrayData()
+    {
+        $out = [];
+
+        $matchQuery = new MatchQuery('foo.bar.aux', 'foo');
+        $nestedQuery = new NestedQuery('foo.bar', $matchQuery);
+        $innerHit = new NestedInnerHit('acme', 'foo', $nestedQuery);
+        $nestedInnerHit1 = new NestedInnerHit('aux', 'foo.bar.aux', $matchQuery);
+        $nestedInnerHit2 = new NestedInnerHit('lux', 'foo.bar.aux', $matchQuery);
+        $innerHit->addInnerHit($nestedInnerHit1);
+        $innerHit->addInnerHit($nestedInnerHit2);
+
+        $out[] = [
+            $nestedInnerHit1,
+            [
+                'path' => [
+                    'foo.bar.aux' => [
+                        'query' => $matchQuery->toArray(),
+                    ],
+                ],
+            ],
+        ];
+
+        $out[] = [
+            $innerHit,
+            [
+                'path' => [
+                    'foo' => [
+                        'query' => $nestedQuery->toArray(),
+                        'inner_hits' => [
+                            'aux' => [
+                                'path' => [
+                                    'foo.bar.aux' => [
+                                        'query' => $matchQuery->toArray(),
+                                    ],
+                                ],
+                            ],
+                            'lux' => [
+                                'path' => [
+                                    'foo.bar.aux' => [
+                                        'query' => $matchQuery->toArray(),
+                                    ],
+                                ],
+                            ]
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        return $out;
+    }
+
+
+    /**
+     * Tests toArray() method.
+     *
+     * @param NestedInnerHit $innerHit
+     * @param array          $expected
+     *
+     * @dataProvider getTestToArrayData
+     */
+    public function testToArray($innerHit, $expected)
+    {
+        $this->assertEquals($expected, $innerHit->toArray());
+    }
+
+
+    /**
+     * Tests getters and setters for $name, $path and $query
+     */
+    public function testGettersAndSetters()
+    {
+        $query = new MatchQuery('acme', 'test');
+        $hit = new NestedInnerHit('test', 'acme', new TermQuery('foo', 'bar'));
+        $hit->setName('foo');
+        $hit->setPath('bar');
+        $hit->setQuery($query);
+
+        $this->assertEquals('foo', $hit->getName());
+        $this->assertEquals('bar', $hit->getPath());
+        $this->assertEquals($query, $hit->getQuery());
+    }
+
+    /**
+     * Tests getInnerHit() method
+     */
+    public function testGetInnerHit()
+    {
+        $query = new MatchQuery('acme', 'test');
+        $hit = new NestedInnerHit('test', 'acme', $query);
+        $nestedInnerHit1 = new NestedInnerHit('foo', 'acme.foo', $query);
+        $nestedInnerHit2 = new NestedInnerHit('bar', 'acme.bar', $query);
+        $hit->addInnerHit($nestedInnerHit1);
+        $hit->addInnerHit($nestedInnerHit2);
+
+        $this->assertEquals($nestedInnerHit1, $hit->getInnerHit('foo'));
+        $this->assertEquals($nestedInnerHit2, $hit->getInnerHit('bar'));
+        $this->assertNull($hit->getInnerHit('non_existing_hit'));
+    }
+}
diff --git a/tests/SearchEndpoint/InnerHitsEndpointTest.php b/tests/SearchEndpoint/InnerHitsEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..268bfccfce931afcb688158a84a315febc8124ef
--- /dev/null
+++ b/tests/SearchEndpoint/InnerHitsEndpointTest.php
@@ -0,0 +1,75 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\SearchEndpoint\InnerHitsEndpoint;
+
+/**
+ * Class AggregationsEndpointTest.
+ */
+class InnerHitsEndpointTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests constructor.
+     */
+    public function testItCanBeInstantiated()
+    {
+        $this->assertInstanceOf(
+            'ONGR\ElasticsearchDSL\SearchEndpoint\InnerHitsEndpoint',
+            new InnerHitsEndpoint()
+        );
+    }
+
+    /**
+     * Tests if endpoint returns builders.
+     */
+    public function testEndpointGetter()
+    {
+        $hitName = 'foo';
+        $innerHit = $this->getMockBuilder('ONGR\ElasticsearchDSL\BuilderInterface')->getMock();
+        $endpoint = new InnerHitsEndpoint();
+        $endpoint->add($innerHit, $hitName);
+        $builders = $endpoint->getAll();
+
+        $this->assertCount(1, $builders);
+        $this->assertSame($innerHit, $builders[$hitName]);
+    }
+
+    /**
+     * Tests normalize method
+     */
+    public function testNormalization()
+    {
+        $normalizer = $this
+            ->getMockBuilder('Symfony\Component\Serializer\Normalizer\NormalizerInterface')
+            ->getMock();
+        $innerHit = $this
+            ->getMockBuilder('ONGR\ElasticsearchDSL\BuilderInterface')
+            ->setMethods(['getName', 'toArray', 'getType'])
+            ->getMock();
+        $innerHit->expects($this->any())->method('getName')->willReturn('foo');
+        $innerHit->expects($this->any())->method('toArray')->willReturn(['foo' => 'bar']);
+
+        $endpoint = new InnerHitsEndpoint();
+        $endpoint->add($innerHit, 'foo');
+        $expected = [
+            'foo' => [
+                'foo' => 'bar'
+            ]
+        ];
+
+        $this->assertEquals(
+            $expected,
+            $endpoint->normalize($normalizer)
+        );
+    }
+}