diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
index e6662b799..ee67a3502 100644
--- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
+++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
@@ -142,6 +142,9 @@ abstract class AbstractHydrator
         $this->_rsm   = $resultSetMapping;
         $this->_hints = $hints;
 
+        $evm = $this->_em->getEventManager();
+        $evm->addEventListener(array(Events::onClear), $this);
+
         $this->prepare();
 
         $result = $this->hydrateAllData();
diff --git a/tests/Doctrine/Tests/ORM/Hydration/AbstractHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/AbstractHydratorTest.php
new file mode 100644
index 000000000..1d02b6c2b
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Hydration/AbstractHydratorTest.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Doctrine\Tests\ORM\Functional\Ticket;
+
+use Doctrine\DBAL\Connection;
+use Doctrine\ORM\EntityManagerInterface;
+use Doctrine\Common\EventManager;
+use Doctrine\DBAL\Driver\Statement;
+use Doctrine\ORM\Events;
+use Doctrine\ORM\Query\ResultSetMapping;
+use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
+use Doctrine\Tests\OrmFunctionalTestCase;
+
+/**
+ * @covers \Doctrine\ORM\Internal\Hydration\AbstractHydrator
+ */
+class AbstractHydratorTest extends OrmFunctionalTestCase
+{
+    /**
+     * @group DDC-3146
+     * @group #1515
+     *
+     * Verify that the number of added events to the event listener from the abstract hydrator class is equal to the
+     * number of removed events
+     */
+    public function testOnClearEventListenerIsDetachedOnCleanup()
+    {
+        $mockConnection             = $this->createMock(Connection::class);
+        $mockEntityManagerInterface = $this->createMock(EntityManagerInterface::class);
+        $mockEventManager           = $this->createMock(EventManager::class);
+        $mockStatement              = $this->createMock(Statement::class);
+        $mockResultMapping          = $this->getMockBuilder(ResultSetMapping::class);
+
+        $mockEntityManagerInterface->expects(self::any())->method('getEventManager')->willReturn($mockEventManager);
+        $mockEntityManagerInterface->expects(self::any())->method('getConnection')->willReturn($mockConnection);
+        $mockStatement->expects(self::once())->method('fetch')->willReturn(false);
+
+        /* @var $mockAbstractHydrator AbstractHydrator */
+        $mockAbstractHydrator = $this
+            ->getMockBuilder(AbstractHydrator::class)
+            ->setConstructorArgs([$mockEntityManagerInterface])
+            ->setMethods(['hydrateAllData'])
+            ->getMock();
+
+        $mockEventManager
+            ->expects(self::at(0))
+            ->method('addEventListener')
+            ->with([Events::onClear], $mockAbstractHydrator);
+
+        $mockEventManager
+            ->expects(self::at(1))
+            ->method('removeEventListener')
+            ->with([Events::onClear], $mockAbstractHydrator);
+
+        $mockEventManager
+            ->expects(self::at(2))
+            ->method('addEventListener')
+            ->with([Events::onClear], $mockAbstractHydrator);
+
+        $mockEventManager
+            ->expects(self::at(3))
+            ->method('removeEventListener')
+            ->with([Events::onClear], $mockAbstractHydrator);
+
+        iterator_to_array($mockAbstractHydrator->iterate($mockStatement, $mockResultMapping));
+        $mockAbstractHydrator->hydrateAll($mockStatement, $mockResultMapping);
+    }
+}