Merge branch 'master' into ignite-1270.
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index cd0c2a2..4985edb 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -1,6 +1,23 @@
 Apache Ignite Release Notes
 ===========================
 
+Apache Ignite In-Memory Data Fabric 1.5
+---------------------------------------
+* Ignite.NET: Initial Release.
+* Ignite C++: Initial Release.
+* Massive performance improvements for cache operations and SQL.
+* Added new binary cache object marshalling implementation.
+* Added IgniteSemaphore data structure.
+* Added MQTT Streamer.
+* Fixed failover for continuous queries.
+* Fixed compilation and runtime errors under OpenJDK and IBM JDK.
+* Fixed Integer.size limitation for cache.
+* Fixed and improved cache types configuration.
+* Fixed cache rebalancing.
+* Many stability and fault-tolerance fixes.
+
+Complete list of closed issues: https://issues.apache.org/jira/issues/?jql=project%20%3D%20IGNITE%20AND%20fixVersion%20%3D%201.5%20AND%20status%20%3D%20closed
+
 Apache Ignite In-Memory Data Fabric 1.4
 ---------------------------------------
 * Added SSL support to communication and discovery.
diff --git a/assembly/release-fabric-base.xml b/assembly/release-fabric-base.xml
index d3e75ba..65903ee 100644
--- a/assembly/release-fabric-base.xml
+++ b/assembly/release-fabric-base.xml
@@ -69,6 +69,15 @@
     </files>
 
     <fileSets>
+        <!-- Move platforms readme. -->
+        <fileSet>
+            <directory>modules/platforms</directory>
+            <outputDirectory>/platforms</outputDirectory>
+            <includes>
+                <include>README.txt</include>
+            </includes>
+        </fileSet>
+
         <!-- Move .Net readme. -->
         <fileSet>
             <directory>modules/platforms/dotnet</directory>
diff --git a/examples/config/binary/example-ignite-binary.xml b/examples/config/binary/example-ignite-binary.xml
deleted file mode 100644
index dbec5e9..0000000
--- a/examples/config/binary/example-ignite-binary.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You under the Apache License, Version 2.0
-  (the "License"); you may not use this file except in compliance with
-  the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-
-<!--
-    Ignite configuration with all defaults and enabled p2p deployment, events and portable marshaller.
-
-    Use this configuration file when running HTTP REST examples (see 'examples/rest' folder).
-
-    When starting a standalone node, you need to execute the following command:
-    {IGNITE_HOME}/bin/ignite.{bat|sh} examples/config/portable/example-ignite-portable.xml
-
-    When starting Ignite from Java IDE, pass path to this file to Ignition:
-    Ignition.start("examples/config/portable/example-ignite-portable.xml");
--->
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-        http://www.springframework.org/schema/beans/spring-beans.xsd">
-    <!-- Imports default Ignite configuration -->
-    <import resource="../example-default.xml"/>
-
-    <bean parent="ignite.cfg">
-        <!-- Enables portable marshaller -->
-        <property name="marshaller">
-            <bean class="org.apache.ignite.marshaller.portable.BinaryMarshaller"/>
-        </property>
-    </bean>
-</beans>
diff --git a/examples/config/example-ignite.xml b/examples/config/example-ignite.xml
index d842a6d..a3e7e22 100644
--- a/examples/config/example-ignite.xml
+++ b/examples/config/example-ignite.xml
@@ -27,13 +27,5 @@
     <!-- Imports default Ignite configuration -->
     <import resource="example-default.xml"/>
 
-    <bean parent="ignite.cfg">
-        <!-- Enabled optimized marshaller -->
-        <property name="marshaller">
-            <bean class="org.apache.ignite.marshaller.optimized.OptimizedMarshaller">
-                <!-- Set to false to allow non-serializable objects in examples, default is true. -->
-                <property name="requireSerializable" value="false"/>
-            </bean>
-        </property>
-    </bean>
+    <bean parent="ignite.cfg"/>
 </beans>
diff --git a/examples/pom.xml b/examples/pom.xml
index e6b235c..819d379 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -124,7 +124,7 @@
                 <dependency>
                     <groupId>org.scalatest</groupId>
                     <artifactId>scalatest_2.11</artifactId>
-                    <version>2.2.2</version>
+                    <version>2.2.4</version>
                     <scope>test</scope>
                     <exclusions>
                         <exclusion>
diff --git a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernatePersonStore.java b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernatePersonStore.java
index d040b88..ade5d18 100644
--- a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernatePersonStore.java
+++ b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernatePersonStore.java
@@ -24,7 +24,7 @@
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.CacheStoreAdapter;
 import org.apache.ignite.cache.store.CacheStoreSession;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.resources.CacheStoreSessionResource;
 import org.hibernate.HibernateException;
@@ -107,7 +107,7 @@
                 for (Object obj : list) {
                     Person person = (Person)obj;
 
-                    clo.apply(person.getId(), person);
+                    clo.apply(person.id, person);
 
                     cnt++;
                 }
diff --git a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java
index f993d81..71c4f68 100644
--- a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java
+++ b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java
@@ -29,7 +29,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.examples.ExampleNodeStartup;
 import org.apache.ignite.examples.ExamplesUtils;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
diff --git a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml
index 035ab98..1314b71 100644
--- a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml
+++ b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml
@@ -23,7 +23,7 @@
         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 
 <hibernate-mapping default-access="field">
-    <class name="org.apache.ignite.examples.datagrid.store.Person" table="PERSONS">
+    <class name="org.apache.ignite.examples.model.Person" table="PERSONS">
         <!-- ID. -->
         <id name="id"/>
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/ExampleBinaryNodeStartup.java b/examples/src/main/java/org/apache/ignite/examples/binary/ExampleBinaryNodeStartup.java
deleted file mode 100644
index 30a015b..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/binary/ExampleBinaryNodeStartup.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.examples.binary;
-
-import org.apache.ignite.IgniteException;
-import org.apache.ignite.Ignition;
-
-/**
- * Starts up an empty node with example configuration and binary marshaller enabled.
- */
-public class ExampleBinaryNodeStartup {
-    /**
-     * Start up an empty node with example configuration and binary marshaller enabled.
-     *
-     * @param args Command line arguments, none required.
-     * @throws IgniteException If failed.
-     */
-    public static void main(String[] args) throws IgniteException {
-        Ignition.start("examples/config/binary/example-ignite-binary.xml");
-    }
-}
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/computegrid/ComputeClientBinaryTaskExecutionExample.java b/examples/src/main/java/org/apache/ignite/examples/binary/computegrid/ComputeClientBinaryTaskExecutionExample.java
index ae5d169..49f254a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/computegrid/ComputeClientBinaryTaskExecutionExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/binary/computegrid/ComputeClientBinaryTaskExecutionExample.java
@@ -22,8 +22,8 @@
 import java.util.Collection;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.Ignition;
-import org.apache.ignite.examples.binary.Address;
-import org.apache.ignite.examples.binary.Employee;
+import org.apache.ignite.examples.model.binary.Address;
+import org.apache.ignite.examples.model.binary.Employee;
 import org.apache.ignite.binary.BinaryObject;
 
 /**
@@ -37,8 +37,8 @@
  * Remote nodes should always be started with special configuration file which
  * enables the binary marshaller: {@code 'ignite.{sh|bat} examples/config/binary/example-ignite-binary.xml'}.
  * <p>
- * Alternatively you can run {@link org.apache.ignite.examples.binary.ExampleBinaryNodeStartup} in another JVM which will
- * start node with {@code examples/config/binary/example-ignite-binary.xml} configuration.
+ * Alternatively you can run {@link org.apache.ignite.examples.ExampleNodeStartup} in another JVM which will
+ * start a node with {@code examples/config/example-ignite.xml} configuration.
  */
 public class ComputeClientBinaryTaskExecutionExample {
     /**
@@ -47,7 +47,7 @@
      * @param args Command line arguments, none required.
      */
     public static void main(String[] args) {
-        try (Ignite ignite = Ignition.start("examples/config/binary/example-ignite-binary.xml")) {
+        try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println();
             System.out.println(">>> Binary objects task execution example started.");
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryPutGetExample.java b/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryPutGetExample.java
index bb88ee0..c416501 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryPutGetExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryPutGetExample.java
@@ -28,9 +28,9 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.examples.binary.Address;
-import org.apache.ignite.examples.binary.Organization;
-import org.apache.ignite.examples.binary.OrganizationType;
+import org.apache.ignite.examples.model.binary.Address;
+import org.apache.ignite.examples.model.binary.Organization;
+import org.apache.ignite.examples.model.binary.OrganizationType;
 import org.apache.ignite.binary.BinaryObject;
 
 /**
@@ -44,8 +44,8 @@
  * Remote nodes should always be started with special configuration file which
  * enables the binary marshaller: {@code 'ignite.{sh|bat} examples/config/binary/example-ignite-binary.xml'}.
  * <p>
- * Alternatively you can run {@link org.apache.ignite.examples.binary.ExampleBinaryNodeStartup} in another JVM which will
- * start node with {@code examples/config/binary/example-ignite-binary.xml} configuration.
+ * Alternatively you can run {@link org.apache.ignite.examples.ExampleNodeStartup} in another JVM which will
+ * start node with {@code examples/config/example-ignite.xml} configuration.
  */
 @SuppressWarnings("TypeMayBeWeakened")
 public class CacheClientBinaryPutGetExample {
@@ -58,7 +58,7 @@
      * @param args Command line arguments, none required.
      */
     public static void main(String[] args) {
-        try (Ignite ignite = Ignition.start("examples/config/binary/example-ignite-binary.xml")) {
+        try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println();
             System.out.println(">>> Binary objects cache put-get example started.");
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryQueryExample.java b/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryQueryExample.java
index c93848c..34452e4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryQueryExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/binary/datagrid/CacheClientBinaryQueryExample.java
@@ -34,19 +34,19 @@
 import org.apache.ignite.cache.query.SqlQuery;
 import org.apache.ignite.cache.query.TextQuery;
 import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.examples.binary.Address;
-import org.apache.ignite.examples.binary.Employee;
-import org.apache.ignite.examples.binary.EmployeeKey;
-import org.apache.ignite.examples.binary.Organization;
-import org.apache.ignite.examples.binary.OrganizationType;
+import org.apache.ignite.examples.model.binary.Address;
+import org.apache.ignite.examples.model.binary.Employee;
+import org.apache.ignite.examples.model.binary.EmployeeKey;
+import org.apache.ignite.examples.model.binary.Organization;
+import org.apache.ignite.examples.model.binary.OrganizationType;
 import org.apache.ignite.binary.BinaryObject;
 
 /**
  * This example demonstrates use of binary objects with cache queries.
  * The example populates cache with sample data and runs several SQL and full text queries over this data.
  * <p>
- * Remote nodes should always be started with {@link org.apache.ignite.examples.binary.ExampleBinaryNodeStartup} which starts a node with
- * {@code examples/config/binary/example-ignite-binary.xml} configuration.
+ * Remote nodes should always be started with {@link org.apache.ignite.examples.ExampleNodeStartup} which starts
+ * a node with {@code examples/config/example-ignite.xml} configuration.
  */
 public class CacheClientBinaryQueryExample {
     /** Organization cache name. */
@@ -63,7 +63,7 @@
      * @param args Command line arguments, none required.
      */
     public static void main(String[] args) {
-        try (Ignite ignite = Ignition.start("examples/config/binary/example-ignite-binary.xml")) {
+        try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
             System.out.println();
             System.out.println(">>> Binary objects cache query example started.");
 
@@ -204,14 +204,14 @@
      * @param cache Ignite cache.
      */
     private static void sqlJoinQuery(IgniteCache<BinaryObject, BinaryObject> cache) {
-        SqlQuery<BinaryObject, BinaryObject> query = new SqlQuery<>(Employee.class,
+        SqlQuery<BinaryObject, BinaryObject> qry = new SqlQuery<>(Employee.class,
             "from Employee, \"" + ORGANIZATION_CACHE_NAME + "\".Organization as org " +
                 "where Employee.organizationId = org._key and org.name = ?");
 
         String organizationName = "GridGain";
 
         QueryCursor<Cache.Entry<BinaryObject, BinaryObject>> employees =
-            cache.query(query.setArgs(organizationName));
+            cache.query(qry.setArgs(organizationName));
 
         System.out.println();
         System.out.println(">>> Employees working for " + organizationName + ':');
@@ -226,9 +226,9 @@
      * @param cache Ignite cache.
      */
     private static void sqlFieldsQuery(IgniteCache<BinaryObject, BinaryObject> cache) {
-        SqlFieldsQuery query = new SqlFieldsQuery("select name, salary from Employee");
+        SqlFieldsQuery qry = new SqlFieldsQuery("select name, salary from Employee");
 
-        QueryCursor<List<?>> employees = cache.query(query);
+        QueryCursor<List<?>> employees = cache.query(qry);
 
         System.out.println();
         System.out.println(">>> Employee names and their salaries:");
@@ -243,9 +243,9 @@
      * @param cache Ignite cache.
      */
     private static void textQuery(IgniteCache<BinaryObject, BinaryObject> cache) {
-        TextQuery<BinaryObject, BinaryObject> query = new TextQuery<>(Employee.class, "TX");
+        TextQuery<BinaryObject, BinaryObject> qry = new TextQuery<>(Employee.class, "TX");
 
-        QueryCursor<Cache.Entry<BinaryObject, BinaryObject>> employees = cache.query(query);
+        QueryCursor<Cache.Entry<BinaryObject, BinaryObject>> employees = cache.query(qry);
 
         System.out.println();
         System.out.println(">>> Employees living in Texas:");
diff --git a/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeFibonacciContinuationExample.java b/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeFibonacciContinuationExample.java
index 706ec18..6642e9d 100644
--- a/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeFibonacciContinuationExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeFibonacciContinuationExample.java
@@ -42,7 +42,9 @@
  * performing the distributed recursive calculation of {@code 'Fibonacci'}
  * numbers on the cluster. Continuations
  * functionality is exposed via {@link ComputeJobContext#holdcc()} and
- * {@link ComputeJobContext#callcc()} method calls in {@link ComputeFibonacciContinuationExample.FibonacciClosure} class.
+ * {@link ComputeJobContext#callcc()} method calls in
+ * {@link org.apache.ignite.examples.computegrid.ComputeFibonacciContinuationExample.ContinuationFibonacciClosure}
+ * class.
  * <p>
  * Remote nodes should always be started with special configuration file which
  * enables P2P class loading: {@code 'ignite.{sh|bat} examples/config/example-ignite.xml'}.
@@ -76,7 +78,8 @@
 
             long start = System.currentTimeMillis();
 
-            BigInteger fib = ignite.compute(ignite.cluster().forPredicate(nodeFilter)).apply(new FibonacciClosure(nodeFilter), N);
+            BigInteger fib = ignite.compute(ignite.cluster().forPredicate(nodeFilter)).apply(
+                new ContinuationFibonacciClosure(nodeFilter), N);
 
             long duration = System.currentTimeMillis() - start;
 
@@ -93,7 +96,7 @@
     /**
      * Closure to execute.
      */
-    private static class FibonacciClosure implements IgniteClosure<Long, BigInteger> {
+    private static class ContinuationFibonacciClosure implements IgniteClosure<Long, BigInteger> {
         /** Future for spawned task. */
         private IgniteFuture<BigInteger> fut1;
 
@@ -114,7 +117,7 @@
         /**
          * @param nodeFilter Predicate to filter nodes.
          */
-        FibonacciClosure(IgnitePredicate<ClusterNode> nodeFilter) {
+        ContinuationFibonacciClosure(IgnitePredicate<ClusterNode> nodeFilter) {
             this.nodeFilter = nodeFilter;
         }
 
@@ -143,7 +146,7 @@
 
                 // If future is not cached in node-local-map, cache it.
                 if (fut1 == null) {
-                    compute.apply(new FibonacciClosure(nodeFilter), n - 1);
+                    compute.apply(new ContinuationFibonacciClosure(nodeFilter), n - 1);
 
                     ComputeTaskFuture<BigInteger> futVal = compute.future();
 
@@ -155,7 +158,7 @@
 
                 // If future is not cached in node-local-map, cache it.
                 if (fut2 == null) {
-                    compute.apply(new FibonacciClosure(nodeFilter), n - 2);
+                    compute.apply(new ContinuationFibonacciClosure(nodeFilter), n - 2);
 
                     ComputeTaskFuture<BigInteger> futVal = compute.<BigInteger>future();
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskMapExample.java b/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskMapExample.java
index 1c880e8..3de5293 100644
--- a/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskMapExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskMapExample.java
@@ -59,7 +59,7 @@
             System.out.println("Compute task map example started.");
 
             // Execute task on the cluster and wait for its completion.
-            int cnt = ignite.compute().execute(CharacterCountTask.class, "Hello Ignite Enabled World!");
+            int cnt = ignite.compute().execute(MapExampleCharacterCountTask.class, "Hello Ignite Enabled World!");
 
             System.out.println();
             System.out.println(">>> Total number of characters in the phrase is '" + cnt + "'.");
@@ -70,7 +70,7 @@
     /**
      * Task to count non-white-space characters in a phrase.
      */
-    private static class CharacterCountTask extends ComputeTaskAdapter<String, Integer> {
+    private static class MapExampleCharacterCountTask extends ComputeTaskAdapter<String, Integer> {
         /**
          * Splits the received string to words, creates a child job for each word, and sends
          * these jobs to other nodes for processing. Each such job simply prints out the received word.
@@ -80,8 +80,6 @@
          * @return Map of jobs to nodes.
          */
         @Override public Map<? extends ComputeJob, ClusterNode> map(List<ClusterNode> nodes, String arg) {
-            String[] words = arg.split(" ");
-
             Map<ComputeJob, ClusterNode> map = new HashMap<>();
 
             Iterator<ClusterNode> it = nodes.iterator();
diff --git a/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskSplitExample.java b/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskSplitExample.java
index a1358e0..60bce4a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskSplitExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/computegrid/ComputeTaskSplitExample.java
@@ -56,7 +56,7 @@
             System.out.println("Compute task split example started.");
 
             // Execute task on the cluster and wait for its completion.
-            int cnt = ignite.compute().execute(CharacterCountTask.class, "Hello Ignite Enabled World!");
+            int cnt = ignite.compute().execute(SplitExampleCharacterCountTask.class, "Hello Ignite Enabled World!");
 
             System.out.println();
             System.out.println(">>> Total number of characters in the phrase is '" + cnt + "'.");
@@ -67,7 +67,7 @@
     /**
      * Task to count non-white-space characters in a phrase.
      */
-    private static class CharacterCountTask extends ComputeTaskSplitAdapter<String, Integer> {
+    private static class SplitExampleCharacterCountTask extends ComputeTaskSplitAdapter<String, Integer> {
         /**
          * Splits the received string to words, creates a child job for each word, and sends
          * these jobs to other nodes for processing. Each such job simply prints out the received word.
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
index 8fba3f6..a593562 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheQueryExample.java
@@ -17,9 +17,7 @@
 
 package org.apache.ignite.examples.datagrid;
 
-import java.io.Serializable;
 import java.util.List;
-import java.util.UUID;
 import javax.cache.Cache;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -31,10 +29,10 @@
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cache.query.SqlQuery;
 import org.apache.ignite.cache.query.TextQuery;
-import org.apache.ignite.cache.query.annotations.QuerySqlField;
-import org.apache.ignite.cache.query.annotations.QueryTextField;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.examples.ExampleNodeStartup;
+import org.apache.ignite.examples.model.Organization;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.lang.IgniteBiPredicate;
 
 /**
@@ -80,19 +78,19 @@
             System.out.println();
             System.out.println(">>> Cache query example started.");
 
-            CacheConfiguration<UUID, Organization> orgCacheCfg = new CacheConfiguration<>(ORG_CACHE);
+            CacheConfiguration<Long, Organization> orgCacheCfg = new CacheConfiguration<>(ORG_CACHE);
 
             orgCacheCfg.setCacheMode(CacheMode.PARTITIONED); // Default.
-            orgCacheCfg.setIndexedTypes(UUID.class, Organization.class);
+            orgCacheCfg.setIndexedTypes(Long.class, Organization.class);
 
-            CacheConfiguration<AffinityKey<UUID>, Person> personCacheCfg = new CacheConfiguration<>(PERSON_CACHE);
+            CacheConfiguration<AffinityKey<Long>, Person> personCacheCfg = new CacheConfiguration<>(PERSON_CACHE);
 
             personCacheCfg.setCacheMode(CacheMode.PARTITIONED); // Default.
             personCacheCfg.setIndexedTypes(AffinityKey.class, Person.class);
 
             try (
-                IgniteCache<UUID, Organization> orgCache = ignite.getOrCreateCache(orgCacheCfg);
-                IgniteCache<AffinityKey<UUID>, Person> personCache = ignite.getOrCreateCache(personCacheCfg)
+                IgniteCache<Long, Organization> orgCache = ignite.getOrCreateCache(orgCacheCfg);
+                IgniteCache<AffinityKey<Long>, Person> personCache = ignite.getOrCreateCache(personCacheCfg)
             ) {
                 // Populate cache.
                 initialize();
@@ -128,11 +126,11 @@
      * Example for scan query based on a predicate.
      */
     private static void scanQuery() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
-        ScanQuery<AffinityKey<UUID>, Person> scan = new ScanQuery<>(
-            new IgniteBiPredicate<AffinityKey<UUID>, Person>() {
-                @Override public boolean apply(AffinityKey<UUID> key, Person person) {
+        ScanQuery<AffinityKey<Long>, Person> scan = new ScanQuery<>(
+            new IgniteBiPredicate<AffinityKey<Long>, Person>() {
+                @Override public boolean apply(AffinityKey<Long> key, Person person) {
                     return person.salary <= 1000;
                 }
             }
@@ -146,18 +144,18 @@
      * Example for SQL queries based on salary ranges.
      */
     private static void sqlQuery() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
         // SQL clause which selects salaries based on range.
         String sql = "salary > ? and salary <= ?";
 
         // Execute queries for salary ranges.
         print("People with salaries between 0 and 1000 (queried with SQL query): ",
-            cache.query(new SqlQuery<AffinityKey<UUID>, Person>(Person.class, sql).
+            cache.query(new SqlQuery<AffinityKey<Long>, Person>(Person.class, sql).
                 setArgs(0, 1000)).getAll());
 
         print("People with salaries between 1000 and 2000 (queried with SQL query): ",
-            cache.query(new SqlQuery<AffinityKey<UUID>, Person>(Person.class, sql).
+            cache.query(new SqlQuery<AffinityKey<Long>, Person>(Person.class, sql).
                 setArgs(1000, 2000)).getAll());
     }
 
@@ -165,7 +163,7 @@
      * Example for SQL queries based on all employees working for a specific organization.
      */
     private static void sqlQueryWithJoin() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
         // SQL clause query which joins on 2 types to select people for a specific organization.
         String joinSql =
@@ -175,11 +173,11 @@
 
         // Execute queries for find employees for different organizations.
         print("Following people are 'ApacheIgnite' employees: ",
-            cache.query(new SqlQuery<AffinityKey<UUID>, Person>(Person.class, joinSql).
+            cache.query(new SqlQuery<AffinityKey<Long>, Person>(Person.class, joinSql).
                 setArgs("ApacheIgnite")).getAll());
 
         print("Following people are 'Other' employees: ",
-            cache.query(new SqlQuery<AffinityKey<UUID>, Person>(Person.class, joinSql).
+            cache.query(new SqlQuery<AffinityKey<Long>, Person>(Person.class, joinSql).
                 setArgs("Other")).getAll());
     }
 
@@ -187,15 +185,15 @@
      * Example for TEXT queries using LUCENE-based indexing of people's resumes.
      */
     private static void textQuery() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
         //  Query for all people with "Master Degree" in their resumes.
-        QueryCursor<Cache.Entry<AffinityKey<UUID>, Person>> masters =
-            cache.query(new TextQuery<AffinityKey<UUID>, Person>(Person.class, "Master"));
+        QueryCursor<Cache.Entry<AffinityKey<Long>, Person>> masters =
+            cache.query(new TextQuery<AffinityKey<Long>, Person>(Person.class, "Master"));
 
         // Query for all people with "Bachelor Degree" in their resumes.
-        QueryCursor<Cache.Entry<AffinityKey<UUID>, Person>> bachelors =
-            cache.query(new TextQuery<AffinityKey<UUID>, Person>(Person.class, "Bachelor"));
+        QueryCursor<Cache.Entry<AffinityKey<Long>, Person>> bachelors =
+            cache.query(new TextQuery<AffinityKey<Long>, Person>(Person.class, "Bachelor"));
 
         print("Following people have 'Master Degree' in their resumes: ", masters.getAll());
         print("Following people have 'Bachelor Degree' in their resumes: ", bachelors.getAll());
@@ -205,7 +203,7 @@
      * Example for SQL queries to calculate average salary for a specific organization.
      */
     private static void sqlQueryWithAggregation() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
         // Calculate average of salary of all persons in ApacheIgnite.
         // Note that we also join on Organization cache as well.
@@ -226,7 +224,7 @@
      * fields instead of whole key-value pairs.
      */
     private static void sqlFieldsQuery() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
         // Execute query to get names of all employees.
         QueryCursor<List<?>> cursor = cache.query(new SqlFieldsQuery(
@@ -244,7 +242,7 @@
      * fields instead of whole key-value pairs.
      */
     private static void sqlFieldsQueryWithJoin() {
-        IgniteCache<AffinityKey<UUID>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> cache = Ignition.ignite().cache(PERSON_CACHE);
 
         // Execute query to get names of all employees.
         String sql =
@@ -265,7 +263,7 @@
      * Populate cache with test data.
      */
     private static void initialize() {
-        IgniteCache<UUID, Organization> orgCache = Ignition.ignite().cache(ORG_CACHE);
+        IgniteCache<Long, Organization> orgCache = Ignition.ignite().cache(ORG_CACHE);
 
         // Organizations.
         Organization org1 = new Organization("ApacheIgnite");
@@ -274,7 +272,7 @@
         orgCache.put(org1.id, org1);
         orgCache.put(org2.id, org2);
 
-        IgniteCache<AffinityKey<UUID>, Person> personCache = Ignition.ignite().cache(PERSON_CACHE);
+        IgniteCache<AffinityKey<Long>, Person> personCache = Ignition.ignite().cache(PERSON_CACHE);
 
         // People.
         Person p1 = new Person(org1, "John", "Doe", 2000, "John Doe has Master Degree.");
@@ -320,109 +318,4 @@
         for (Object next : col)
             System.out.println(">>>     " + next);
     }
-
-    /**
-     * Person class.
-     */
-    private static class Person implements Serializable {
-        /** Person ID (indexed). */
-        @QuerySqlField(index = true)
-        private UUID id;
-
-        /** Organization ID (indexed). */
-        @QuerySqlField(index = true)
-        private UUID orgId;
-
-        /** First name (not-indexed). */
-        @QuerySqlField
-        private String firstName;
-
-        /** Last name (not indexed). */
-        @QuerySqlField
-        private String lastName;
-
-        /** Resume text (create LUCENE-based TEXT index for this field). */
-        @QueryTextField
-        private String resume;
-
-        /** Salary (indexed). */
-        @QuerySqlField(index = true)
-        private double salary;
-
-        /** Custom cache key to guarantee that person is always collocated with its organization. */
-        private transient AffinityKey<UUID> key;
-
-        /**
-         * Constructs person record.
-         *
-         * @param org Organization.
-         * @param firstName First name.
-         * @param lastName Last name.
-         * @param salary Salary.
-         * @param resume Resume text.
-         */
-        Person(Organization org, String firstName, String lastName, double salary, String resume) {
-            // Generate unique ID for this person.
-            id = UUID.randomUUID();
-
-            orgId = org.id;
-
-            this.firstName = firstName;
-            this.lastName = lastName;
-            this.resume = resume;
-            this.salary = salary;
-        }
-
-        /**
-         * Gets cache affinity key. Since in some examples person needs to be collocated with organization, we create
-         * custom affinity key to guarantee this collocation.
-         *
-         * @return Custom affinity key to guarantee that person is always collocated with organization.
-         */
-        public AffinityKey<UUID> key() {
-            if (key == null)
-                key = new AffinityKey<>(id, orgId);
-
-            return key;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return "Person [firstName=" + firstName +
-                ", lastName=" + lastName +
-                ", id=" + id +
-                ", orgId=" + orgId +
-                ", resume=" + resume +
-                ", salary=" + salary + ']';
-        }
-    }
-
-    /**
-     * Organization class.
-     */
-    private static class Organization implements Serializable {
-        /** Organization ID (indexed). */
-        @QuerySqlField(index = true)
-        private UUID id;
-
-        /** Organization name (indexed). */
-        @QuerySqlField(index = true)
-        private String name;
-
-        /**
-         * Create organization.
-         *
-         * @param name Organization name.
-         */
-        Organization(String name) {
-            id = UUID.randomUUID();
-
-            this.name = name;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return "Organization [id=" + id + ", name=" + name + ']';
-        }
-    }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/Person.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/Person.java
deleted file mode 100644
index b54010f..0000000
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/Person.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.examples.datagrid.store;
-
-import java.io.Serializable;
-
-/**
- * Person definition.
- *
- * Code generated by Apache Ignite Schema Import utility: 02/24/2015.
- */
-public class Person implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** Value for id. */
-    private long id;
-
-    /** Value for first name. */
-    private String firstName;
-
-    /** Value for last name. */
-    private String lastName;
-
-    /**
-     * Empty constructor.
-     */
-    public Person() {
-        // No-op.
-    }
-
-    /**
-     * Full constructor.
-     */
-    public Person(
-        long id,
-        String firstName,
-        String lastName
-    ) {
-        this.id = id;
-        this.firstName = firstName;
-        this.lastName = lastName;
-    }
-
-    /**
-     * Gets id.
-     *
-     * @return Value for id.
-     */
-    public long getId() {
-        return id;
-    }
-
-    /**
-     * Sets id.
-     *
-     * @param id New value for id.
-     */
-    public void setId(long id) {
-        this.id = id;
-    }
-
-    /**
-     * Gets first name.
-     *
-     * @return Value for first name.
-     */
-    public String getFirstName() {
-        return firstName;
-    }
-
-    /**
-     * Sets first name.
-     *
-     * @param firstName New value for first name.
-     */
-    public void setFirstName(String firstName) {
-        this.firstName = firstName;
-    }
-
-    /**
-     * Gets last name.
-     *
-     * @return Value for last name.
-     */
-    public String getLastName() {
-        return lastName;
-    }
-
-    /**
-     * Sets last name.
-     *
-     * @param lastName New value for last name.
-     */
-    public void setLastName(String lastName) {
-        this.lastName = lastName;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object o) {
-        if (this == o)
-            return true;
-
-        if (!(o instanceof Person))
-            return false;
-
-        Person that = (Person)o;
-
-        if (id != that.id)
-            return false;
-
-        if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null)
-            return false;
-
-        if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null)
-            return false;
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        int res = (int)(id ^ (id >>> 32));
-
-        res = 31 * res + (firstName != null ? firstName.hashCode() : 0);
-
-        res = 31 * res + (lastName != null ? lastName.hashCode() : 0);
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return "Person [id=" + id +
-            ", firstName=" + firstName +
-            ", lastName=" + lastName +
-            "]";
-    }
-}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreExample.java
index f8cd4dd..37a31d7 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreExample.java
@@ -24,7 +24,7 @@
 import org.apache.ignite.Ignition;
 import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore;
 import org.apache.ignite.examples.ExampleNodeStartup;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.transactions.Transaction;
 
 /**
@@ -85,4 +85,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreLoadDataExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreLoadDataExample.java
index f0f9feb..63a8c6f 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreLoadDataExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheAutoStoreLoadDataExample.java
@@ -25,7 +25,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.examples.ExampleNodeStartup;
 import org.apache.ignite.examples.ExamplesUtils;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 
 /**
  * Demonstrates how to load data from database.
@@ -82,4 +82,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheConfig.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheConfig.java
index 1eb7cd2..3b38aeb 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheConfig.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/auto/CacheConfig.java
@@ -26,7 +26,7 @@
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore;
 import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.h2.jdbcx.JdbcConnectionPool;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -59,7 +59,7 @@
         meta.setDatabaseTable("PERSON");
 
         meta.setKeyType("java.lang.Long");
-        meta.setValueType("org.apache.ignite.examples.datagrid.store.Person");
+        meta.setValueType("org.apache.ignite.examples.model.Person");
 
         meta.setKeyFields(Collections.singletonList(new CacheTypeFieldMetadata("ID", Types.BIGINT, "id", Long.class)));
 
@@ -78,4 +78,4 @@
 
         return cfg;
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyPersonStore.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyPersonStore.java
index f85e92b..6c0fecb 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyPersonStore.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyPersonStore.java
@@ -22,7 +22,7 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.cache.store.CacheStoreAdapter;
 import org.apache.ignite.cache.store.CacheStoreSession;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.resources.CacheNameResource;
 import org.apache.ignite.resources.CacheStoreSessionResource;
@@ -85,7 +85,7 @@
 
         System.out.println(">>> Store loadCache for entry count: " + cnt);
 
-        for (int i = 0; i < cnt; i++) {
+        for (long i = 0; i < cnt; i++) {
             // Generate dummy person on the fly.
             Person p = new Person(i, "first-" + i, "last-" + 1);
 
@@ -93,13 +93,13 @@
             // but we check if local node is primary or backup anyway just to demonstrate that we can.
             // Ideally, partition ID of a key would be stored  in the database and only keys
             // for partitions that belong on this node would be loaded from database.
-            if (ignite.affinity(cacheName).isPrimaryOrBackup(ignite.cluster().localNode(), p.getId())) {
+            if (ignite.affinity(cacheName).isPrimaryOrBackup(ignite.cluster().localNode(), p.id)) {
                 // Update dummy database.
                 // In real life data would be loaded from database.
-                dummyDB.put(p.getId(), p);
+                dummyDB.put(p.id, p);
 
                 // Pass data to cache.
-                clo.apply(p.getId(), p);
+                clo.apply(p.id, p);
             }
         }
     }
@@ -110,4 +110,4 @@
     @Nullable private Transaction transaction() {
         return ses != null ? ses.transaction() : null;
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyStoreExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyStoreExample.java
index 20e6b8f..a631df3 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyStoreExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/dummy/CacheDummyStoreExample.java
@@ -26,7 +26,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.examples.ExampleNodeStartup;
 import org.apache.ignite.examples.ExamplesUtils;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -130,4 +130,4 @@
 
         System.out.println("Read value after commit: " + cache.get(id));
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcPersonStore.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcPersonStore.java
index e0ea13a..6ba181e 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcPersonStore.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcPersonStore.java
@@ -29,7 +29,7 @@
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.CacheStoreAdapter;
 import org.apache.ignite.cache.store.CacheStoreSession;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.resources.CacheStoreSessionResource;
 import org.h2.jdbcx.JdbcConnectionPool;
@@ -107,9 +107,9 @@
             // Some databases would allow these to be done in one 'upsert' operation.
             try (PreparedStatement st = conn.prepareStatement(
                 "update PERSONS set firstName = ?, lastName = ? where id = ?")) {
-                st.setString(1, val.getFirstName());
-                st.setString(2, val.getLastName());
-                st.setLong(3, val.getId());
+                st.setString(1, val.firstName);
+                st.setString(2, val.lastName);
+                st.setLong(3, val.id);
 
                 updated = st.executeUpdate();
             }
@@ -118,9 +118,9 @@
             if (updated == 0) {
                 try (PreparedStatement st = conn.prepareStatement(
                     "insert into PERSONS (id, firstName, lastName) values (?, ?, ?)")) {
-                    st.setLong(1, val.getId());
-                    st.setString(2, val.getFirstName());
-                    st.setString(3, val.getLastName());
+                    st.setLong(1, val.id);
+                    st.setString(2, val.firstName);
+                    st.setString(3, val.lastName);
 
                     st.executeUpdate();
                 }
@@ -166,7 +166,7 @@
             while (rs.next()) {
                 Person person = new Person(rs.getLong(1), rs.getString(2), rs.getString(3));
 
-                clo.apply(person.getId(), person);
+                clo.apply(person.id, person);
 
                 cnt++;
             }
@@ -177,4 +177,4 @@
             throw new CacheLoaderException("Failed to load values from cache store.", e);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcStoreExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcStoreExample.java
index 9d3014f..55ad5df 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcStoreExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/jdbc/CacheJdbcStoreExample.java
@@ -29,7 +29,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.examples.ExampleNodeStartup;
 import org.apache.ignite.examples.ExamplesUtils;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -144,4 +144,4 @@
 
         System.out.println("Read value after commit: " + cache.get(id));
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java
index 7a0ea33..0029890 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java
@@ -26,7 +26,7 @@
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.CacheStoreAdapter;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -92,11 +92,11 @@
         System.out.println(">>> Store write [key=" + key + ", val=" + val + ']');
 
         int updated = jdbcTemplate.update("update PERSONS set firstName = ?, lastName = ? where id = ?",
-            val.getFirstName(), val.getLastName(), val.getId());
+            val.firstName, val.lastName, val.id);
 
         if (updated == 0) {
             jdbcTemplate.update("insert into PERSONS (id, firstName, lastName) values (?, ?, ?)",
-                val.getId(), val.getFirstName(), val.getLastName());
+                val.id, val.firstName, val.lastName);
         }
     }
 
@@ -120,7 +120,7 @@
             @Override public void processRow(ResultSet rs) throws SQLException {
                 Person person = new Person(rs.getLong(1), rs.getString(2), rs.getString(3));
 
-                clo.apply(person.getId(), person);
+                clo.apply(person.id, person);
 
                 cnt.incrementAndGet();
             }
@@ -128,4 +128,4 @@
 
         System.out.println(">>> Loaded " + cnt + " values into cache.");
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java
index 16437da..273ea1c 100644
--- a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java
@@ -29,7 +29,7 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.examples.ExampleNodeStartup;
 import org.apache.ignite.examples.ExamplesUtils;
-import org.apache.ignite.examples.datagrid.store.Person;
+import org.apache.ignite.examples.model.Person;
 import org.apache.ignite.transactions.Transaction;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
@@ -144,4 +144,4 @@
 
         System.out.println("Read value after commit: " + cache.get(id));
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/messaging/MessagingExample.java b/examples/src/main/java/org/apache/ignite/examples/messaging/MessagingExample.java
index 8f37d59..a810e02 100644
--- a/examples/src/main/java/org/apache/ignite/examples/messaging/MessagingExample.java
+++ b/examples/src/main/java/org/apache/ignite/examples/messaging/MessagingExample.java
@@ -47,7 +47,7 @@
     private static final int MESSAGES_NUM = 10;
 
     /** Message topics. */
-    private enum TOPIC { ORDERED, UNORDERED }
+    private enum EXAMPLE_TOPIC { ORDERED, UNORDERED }
 
     /**
      * Executes example.
@@ -79,13 +79,13 @@
 
             // Send unordered messages to all remote nodes.
             for (int i = 0; i < MESSAGES_NUM; i++)
-                ignite.message(rmts).send(TOPIC.UNORDERED, Integer.toString(i));
+                ignite.message(rmts).send(EXAMPLE_TOPIC.UNORDERED, Integer.toString(i));
 
             System.out.println(">>> Finished sending unordered messages.");
 
             // Send ordered messages to all remote nodes.
             for (int i = 0; i < MESSAGES_NUM; i++)
-                ignite.message(rmts).sendOrdered(TOPIC.ORDERED, Integer.toString(i), 0);
+                ignite.message(rmts).sendOrdered(EXAMPLE_TOPIC.ORDERED, Integer.toString(i), 0);
 
             System.out.println(">>> Finished sending ordered messages.");
             System.out.println(">>> Check output on all nodes for message printouts.");
@@ -105,7 +105,7 @@
      */
     private static void startListening(IgniteMessaging msg) {
         // Add ordered message listener.
-        msg.remoteListen(TOPIC.ORDERED, new IgniteBiPredicate<UUID, String>() {
+        msg.remoteListen(EXAMPLE_TOPIC.ORDERED, new IgniteBiPredicate<UUID, String>() {
             @IgniteInstanceResource
             private Ignite ignite;
 
@@ -113,7 +113,7 @@
                 System.out.println("Received ordered message [msg=" + msg + ", fromNodeId=" + nodeId + ']');
 
                 try {
-                    ignite.message(ignite.cluster().forNodeId(nodeId)).send(TOPIC.ORDERED, msg);
+                    ignite.message(ignite.cluster().forNodeId(nodeId)).send(EXAMPLE_TOPIC.ORDERED, msg);
                 }
                 catch (IgniteException e) {
                     e.printStackTrace();
@@ -124,7 +124,7 @@
         });
 
         // Add unordered message listener.
-        msg.remoteListen(TOPIC.UNORDERED, new IgniteBiPredicate<UUID, String>() {
+        msg.remoteListen(EXAMPLE_TOPIC.UNORDERED, new IgniteBiPredicate<UUID, String>() {
             @IgniteInstanceResource
             private Ignite ignite;
 
@@ -132,7 +132,7 @@
                 System.out.println("Received unordered message [msg=" + msg + ", fromNodeId=" + nodeId + ']');
 
                 try {
-                    ignite.message(ignite.cluster().forNodeId(nodeId)).send(TOPIC.UNORDERED, msg);
+                    ignite.message(ignite.cluster().forNodeId(nodeId)).send(EXAMPLE_TOPIC.UNORDERED, msg);
                 }
                 catch (IgniteException e) {
                     e.printStackTrace();
@@ -155,7 +155,7 @@
         final CountDownLatch orderedLatch,
         final CountDownLatch unorderedLatch
     ) {
-        msg.localListen(TOPIC.ORDERED, new IgniteBiPredicate<UUID, String>() {
+        msg.localListen(EXAMPLE_TOPIC.ORDERED, new IgniteBiPredicate<UUID, String>() {
             @Override public boolean apply(UUID nodeId, String msg) {
                 orderedLatch.countDown();
 
@@ -164,7 +164,7 @@
             }
         });
 
-        msg.localListen(TOPIC.UNORDERED, new IgniteBiPredicate<UUID, String>() {
+        msg.localListen(EXAMPLE_TOPIC.UNORDERED, new IgniteBiPredicate<UUID, String>() {
             @Override public boolean apply(UUID nodeId, String msg) {
                 unorderedLatch.countDown();
 
diff --git a/examples/src/main/java/org/apache/ignite/examples/misc/springbean/spring-bean.xml b/examples/src/main/java/org/apache/ignite/examples/misc/springbean/spring-bean.xml
index 393b9cf..b9fcb86 100644
--- a/examples/src/main/java/org/apache/ignite/examples/misc/springbean/spring-bean.xml
+++ b/examples/src/main/java/org/apache/ignite/examples/misc/springbean/spring-bean.xml
@@ -35,13 +35,6 @@
                 <!-- Set to true to enable ignite-aware class loading for examples, default is false. -->
                 <property name="peerClassLoadingEnabled" value="true"/>
 
-                <property name="marshaller">
-                    <bean class="org.apache.ignite.marshaller.optimized.OptimizedMarshaller">
-                        <!-- Set to false to allow non-serializable objects in examples, default is true. -->
-                        <property name="requireSerializable" value="false"/>
-                    </bean>
-                </property>
-
                 <!-- Enable task execution events for examples. -->
                 <property name="includeEventTypes">
                     <util:constant static-field="org.apache.ignite.events.EventType.EVTS_TASK_EXECUTION"/>
diff --git a/examples/src/main/java/org/apache/ignite/examples/model/Organization.java b/examples/src/main/java/org/apache/ignite/examples/model/Organization.java
new file mode 100644
index 0000000..3dcaa44
--- /dev/null
+++ b/examples/src/main/java/org/apache/ignite/examples/model/Organization.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.examples.model;
+
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+
+import java.io.Serializable;
+import java.util.Random;
+
+/**
+ * Organization class.
+ */
+public class Organization implements Serializable {
+    /** */
+    private static final Random RND = new Random();
+
+    /** Organization ID (indexed). */
+    @QuerySqlField(index = true)
+    public Long id;
+
+    /** Organization name (indexed). */
+    @QuerySqlField(index = true)
+    public String name;
+
+    /**
+     * Default empty constructor.
+     */
+    public Organization() {
+        // No-op.
+    }
+
+    /**
+     * Create organization.
+     *
+     * @param name Organization name.
+     */
+    public Organization(String name) {
+        id = RND.nextLong();
+
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "Organization [id=" + id + ", name=" + name + ']';
+    }
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/model/Person.java b/examples/src/main/java/org/apache/ignite/examples/model/Person.java
new file mode 100644
index 0000000..5ccda51
--- /dev/null
+++ b/examples/src/main/java/org/apache/ignite/examples/model/Person.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.examples.model;
+
+import org.apache.ignite.cache.affinity.AffinityKey;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.cache.query.annotations.QueryTextField;
+
+import java.io.Serializable;
+import java.util.Random;
+
+/**
+ * Person class.
+ */
+public class Person implements Serializable {
+    /** */
+    private static final Random RND = new Random();
+
+    /** Person ID (indexed). */
+    @QuerySqlField(index = true)
+    public Long id;
+
+    /** Organization ID (indexed). */
+    @QuerySqlField(index = true)
+    public Long orgId;
+
+    /** First name (not-indexed). */
+    @QuerySqlField
+    public String firstName;
+
+    /** Last name (not indexed). */
+    @QuerySqlField
+    public String lastName;
+
+    /** Resume text (create LUCENE-based TEXT index for this field). */
+    @QueryTextField
+    public String resume;
+
+    /** Salary (indexed). */
+    @QuerySqlField(index = true)
+    public double salary;
+
+    /** Custom cache key to guarantee that person is always collocated with its organization. */
+    private transient AffinityKey<Long> key;
+
+    /**
+     * Default empty constructor.
+     */
+    public Person() {
+        // No-op.
+    }
+
+    /**
+     * Constructs person record.
+     *
+     * @param org       Organization.
+     * @param firstName First name.
+     * @param lastName  Last name.
+     * @param salary    Salary.
+     * @param resume    Resume text.
+     */
+    public Person(Organization org, String firstName, String lastName, double salary, String resume) {
+        // Generate unique ID for this person.
+        id = RND.nextLong();
+
+        orgId = org.id;
+
+        this.firstName = firstName;
+        this.lastName = lastName;
+        this.resume = resume;
+        this.salary = salary;
+    }
+
+    /**
+     * Constructs person record.
+     *
+     * @param id Person ID.
+     * @param firstName First name.
+     * @param lastName Last name.
+     */
+    public Person(Long id, String firstName, String lastName) {
+        this.id = id;
+
+        this.firstName = firstName;
+        this.lastName = lastName;
+    }
+
+    /**
+     * Gets cache affinity key. Since in some examples person needs to be collocated with organization, we create
+     * custom affinity key to guarantee this collocation.
+     *
+     * @return Custom affinity key to guarantee that person is always collocated with organization.
+     */
+    public AffinityKey<Long> key() {
+        if (key == null)
+            key = new AffinityKey<>(id, orgId);
+
+        return key;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String toString() {
+        return "Person [firstName=" + firstName +
+                ", lastName=" + lastName +
+                ", id=" + id +
+                ", orgId=" + orgId +
+                ", resume=" + resume +
+                ", salary=" + salary + ']';
+    }
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/Address.java b/examples/src/main/java/org/apache/ignite/examples/model/binary/Address.java
similarity index 97%
rename from examples/src/main/java/org/apache/ignite/examples/binary/Address.java
rename to examples/src/main/java/org/apache/ignite/examples/model/binary/Address.java
index 76d8774..2d17cb8 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/Address.java
+++ b/examples/src/main/java/org/apache/ignite/examples/model/binary/Address.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.examples.model.binary;
 
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.Binarylizable;
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/Employee.java b/examples/src/main/java/org/apache/ignite/examples/model/binary/Employee.java
similarity index 87%
rename from examples/src/main/java/org/apache/ignite/examples/binary/Employee.java
rename to examples/src/main/java/org/apache/ignite/examples/model/binary/Employee.java
index 744b44f..ad82065 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/Employee.java
+++ b/examples/src/main/java/org/apache/ignite/examples/model/binary/Employee.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.examples.model.binary;
 
 import java.util.Collection;
 
@@ -30,7 +30,7 @@
     private long salary;
 
     /** Address. */
-    private Address address;
+    private Address addr;
 
     /** Departments. */
     private Collection<String> departments;
@@ -45,13 +45,13 @@
     /**
      * @param name Name.
      * @param salary Salary.
-     * @param address Address.
+     * @param addr Address.
      * @param departments Departments.
      */
-    public Employee(String name, long salary, Address address, Collection<String> departments) {
+    public Employee(String name, long salary, Address addr, Collection<String> departments) {
         this.name = name;
         this.salary = salary;
-        this.address = address;
+        this.addr = addr;
         this.departments = departments;
     }
 
@@ -73,7 +73,7 @@
      * @return Address.
      */
     public Address address() {
-        return address;
+        return addr;
     }
 
     /**
@@ -87,7 +87,7 @@
     @Override public String toString() {
         return "Employee [name=" + name +
             ", salary=" + salary +
-            ", address=" + address +
+            ", address=" + addr +
             ", departments=" + departments + ']';
     }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/EmployeeKey.java b/examples/src/main/java/org/apache/ignite/examples/model/binary/EmployeeKey.java
similarity index 94%
rename from examples/src/main/java/org/apache/ignite/examples/binary/EmployeeKey.java
rename to examples/src/main/java/org/apache/ignite/examples/model/binary/EmployeeKey.java
index 2794230..20367ac 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/EmployeeKey.java
+++ b/examples/src/main/java/org/apache/ignite/examples/model/binary/EmployeeKey.java
@@ -15,7 +15,9 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.examples.model.binary;
+
+import org.apache.ignite.cache.affinity.AffinityKeyMapped;
 
 /**
  * This class represents key for employee object.
@@ -28,6 +30,7 @@
     private int id;
 
     /** Organization ID. */
+    @AffinityKeyMapped
     private int organizationId;
 
     /**
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/Organization.java b/examples/src/main/java/org/apache/ignite/examples/model/binary/Organization.java
similarity index 86%
rename from examples/src/main/java/org/apache/ignite/examples/binary/Organization.java
rename to examples/src/main/java/org/apache/ignite/examples/model/binary/Organization.java
index b42bb27a..6b7aca4 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/Organization.java
+++ b/examples/src/main/java/org/apache/ignite/examples/model/binary/Organization.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.examples.model.binary;
 
 import java.sql.Timestamp;
 
@@ -27,7 +27,7 @@
     private String name;
 
     /** Address. */
-    private Address address;
+    private Address addr;
 
     /** Type. */
     private OrganizationType type;
@@ -44,13 +44,13 @@
 
     /**
      * @param name Name.
-     * @param address Address.
+     * @param addr Address.
      * @param type Type.
      * @param lastUpdated Last update time.
      */
-    public Organization(String name, Address address, OrganizationType type, Timestamp lastUpdated) {
+    public Organization(String name, Address addr, OrganizationType type, Timestamp lastUpdated) {
         this.name = name;
-        this.address = address;
+        this.addr = addr;
         this.type = type;
         this.lastUpdated = lastUpdated;
     }
@@ -66,7 +66,7 @@
      * @return Address.
      */
     public Address address() {
-        return address;
+        return addr;
     }
 
     /**
@@ -86,7 +86,7 @@
     /** {@inheritDoc} */
     @Override public String toString() {
         return "Organization [name=" + name +
-            ", address=" + address +
+            ", address=" + addr +
             ", type=" + type +
             ", lastUpdated=" + lastUpdated + ']';
     }
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/examples/src/main/java/org/apache/ignite/examples/model/binary/OrganizationType.java
similarity index 95%
rename from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
rename to examples/src/main/java/org/apache/ignite/examples/model/binary/OrganizationType.java
index 6548210..69804c0 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/examples/src/main/java/org/apache/ignite/examples/model/binary/OrganizationType.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.examples.model.binary;
 
 /**
  * Organization type enum.
diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheExample.scala
index 0bf8d6f..32afab2 100644
--- a/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheExample.scala
+++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheExample.scala
@@ -49,6 +49,10 @@
 
             basicOperations()
         }
+        catch {
+            case e: Throwable =>
+                e.printStackTrace();
+        }
         finally {
             cache.destroy()
         }
@@ -78,13 +82,20 @@
         // Put one more value.
         c += (3.toString -> 11)
 
-        // Get with option...
-        c.opt(44.toString) match {
-            case Some(v) => sys.error("Should never happen.")
-            case None => println("Correct")
+        try {
+            c.opt(44.toString) match {
+                case Some(v) => sys.error("Should never happen.")
+                case _ => println("Correct")
+            }
+        }
+        catch {
+            case e: Throwable =>
+                e.printStackTrace()
         }
 
+
         // Print all values.
+        println("Print all values.")
         c.iterator() foreach println
     }
 
diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheQueryExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheQueryExample.scala
index 1a42947..6d6c8c3 100644
--- a/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheQueryExample.scala
+++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/ScalarCacheQueryExample.scala
@@ -17,11 +17,13 @@
 
 package org.apache.ignite.scalar.examples
 
+import java.lang.{Long => JLong}
 import java.util._
 
 import org.apache.ignite.cache.CacheMode._
 import org.apache.ignite.cache.affinity.AffinityKey
 import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.examples.model.{Person, Organization}
 import org.apache.ignite.scalar.scalar
 import org.apache.ignite.scalar.scalar._
 import org.apache.ignite.{Ignite, IgniteCache}
@@ -48,7 +50,7 @@
      */
     def main(args: Array[String]) {
         scalar(CONFIG) {
-            val cache = createCache$(NAME, indexedTypes = Seq(classOf[UUID], classOf[Organization],
+            val cache = createCache$(NAME, indexedTypes = Seq(classOf[JLong], classOf[Organization],
                 classOf[AffinityKey[_]], classOf[Person]))
 
             try {
@@ -70,12 +72,12 @@
         initialize()
 
         // Cache instance shortcut.
-        val cache = mkCache[AffinityKey[UUID], Person]
+        val cache = mkCache[AffinityKey[JLong], Person]
 
         // Using distributed queries for partitioned cache and local queries for replicated cache.
         // Since in replicated caches data is available on all nodes, including local one,
         // it is enough to just query the local node.
-        val prj = if (cache.getConfiguration(classOf[CacheConfiguration[AffinityKey[UUID], Person]]).getCacheMode == PARTITIONED)
+        val prj = if (cache.getConfiguration(classOf[CacheConfiguration[AffinityKey[JLong], Person]]).getCacheMode == PARTITIONED)
             ignite.cluster().forRemotes()
         else
             ignite.cluster().forLocal()
@@ -104,23 +106,23 @@
         cache$(NAME).get.clear()
 
         // Organization cache projection.
-        val orgCache = mkCache[UUID, Organization]
+        val orgCache = mkCache[JLong, Organization]
 
         // Organizations.
-        val org1 = Organization("Ignite")
-        val org2 = Organization("Other")
+        val org1 = new Organization("Ignite")
+        val org2 = new Organization("Other")
 
         orgCache += (org1.id -> org1)
         orgCache += (org2.id -> org2)
 
         // Person cache projection.
-        val prnCache = mkCache[AffinityKey[UUID], Person]
+        val prnCache = mkCache[AffinityKey[JLong], Person]
 
         // People.
-        val p1 = Person(org1, "John", "Doe", 2000, "John Doe has Master Degree.")
-        val p2 = Person(org1, "Jane", "Doe", 1000, "Jane Doe has Bachelor Degree.")
-        val p3 = Person(org2, "John", "Smith", 1500, "John Smith has Bachelor Degree.")
-        val p4 = Person(org2, "Jane", "Smith", 2500, "Jane Smith has Master Degree.")
+        val p1 = new Person(org1, "John", "Doe", 2000, "John Doe has Master Degree.")
+        val p2 = new Person(org1, "Jane", "Doe", 1000, "Jane Doe has Bachelor Degree.")
+        val p3 = new Person(org2, "John", "Smith", 1500, "John Smith has Bachelor Degree.")
+        val p4 = new Person(org2, "Jane", "Smith", 2500, "Jane Smith has Master Degree.")
 
         // Note that in this example we use custom affinity key for Person objects
         // to ensure that all persons are collocated with their organizations.
@@ -148,45 +150,3 @@
         }
     }
 }
-
-/**
- * Organization class.
- */
-private case class Organization(
-    @ScalarCacheQuerySqlField
-    name: String
-) {
-    /** Organization ID. */
-    @ScalarCacheQuerySqlField
-    val id = UUID.randomUUID
-}
-
-/**
- * Person class.
- */
-private case class Person(
-    org: Organization,
-    firstName: String,
-    lastName: String,
-    @ScalarCacheQuerySqlField
-    salary: Double,
-    @ScalarCacheQueryTextField
-    resume: String
-) {
-    /** Person ID. */
-    val id = UUID.randomUUID
-
-    /** Organization ID. */
-    @ScalarCacheQuerySqlField
-    val orgId = org.id
-
-    /** Affinity key for this person. */
-    val key = new AffinityKey[UUID](id, org.id)
-
-    /**
-     * `toString` implementation.
-     */
-    override def toString: String = {
-        firstName + " " + lastName + " [salary: " + salary + ", resume: " + resume + "]"
-    }
-}
diff --git a/examples/src/test/java/org/apache/ignite/testsuites/IgniteExamplesSelfTestSuite.java b/examples/src/test/java/org/apache/ignite/testsuites/IgniteExamplesSelfTestSuite.java
index f68ce95..4412af3 100644
--- a/examples/src/test/java/org/apache/ignite/testsuites/IgniteExamplesSelfTestSuite.java
+++ b/examples/src/test/java/org/apache/ignite/testsuites/IgniteExamplesSelfTestSuite.java
@@ -59,8 +59,8 @@
      * @throws Exception If failed.
      */
     public static TestSuite suite() throws Exception {
-        System.setProperty(IGNITE_OVERRIDE_MCAST_GRP,
-            GridTestUtils.getNextMulticastGroup(IgniteExamplesSelfTestSuite.class));
+//        System.setProperty(IGNITE_OVERRIDE_MCAST_GRP,
+//            GridTestUtils.getNextMulticastGroup(IgniteExamplesSelfTestSuite.class));
 
         TestSuite suite = new TestSuite("Ignite Examples Test Suite");
 
diff --git a/modules/camel/src/main/java/org/apache/ignite/stream/camel/package-info.java b/modules/camel/src/main/java/org/apache/ignite/stream/camel/package-info.java
new file mode 100644
index 0000000..f084813
--- /dev/null
+++ b/modules/camel/src/main/java/org/apache/ignite/stream/camel/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Camel Streamer.
+ */
+package org.apache.ignite.stream.camel;
\ No newline at end of file
diff --git a/modules/camel/src/test/java/org/apache/ignite/stream/camel/package-info.java b/modules/camel/src/test/java/org/apache/ignite/stream/camel/package-info.java
new file mode 100644
index 0000000..f084813
--- /dev/null
+++ b/modules/camel/src/test/java/org/apache/ignite/stream/camel/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Camel Streamer.
+ */
+package org.apache.ignite.stream.camel;
\ No newline at end of file
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/client/router/RouterFactorySelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/client/router/RouterFactorySelfTest.java
index d5eee7f..2e9e62a 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/client/router/RouterFactorySelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/client/router/RouterFactorySelfTest.java
@@ -105,6 +105,8 @@
         }
         finally {
             GridRouterFactory.stopAllRouters();
+
+            stopAllGrids();
         }
     }
 }
\ No newline at end of file
diff --git a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
index 5a31415..8733bb3 100644
--- a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
+++ b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
@@ -44,6 +44,7 @@
 import org.apache.ignite.internal.GridDirectTransient;
 import org.apache.ignite.internal.IgniteCodeGeneratingFail;
 import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateRequest;
+import org.apache.ignite.internal.processors.cache.query.continuous.CacheContinuousQueryEntry;
 import org.apache.ignite.internal.util.UUIDCollectionMessage;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java b/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java
index 8802c10..a1c656b 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteBinary.java
@@ -134,7 +134,7 @@
  * <h1 class="header">Portable Metadata</h1>
  * Even though Ignite portable protocol only works with hash codes for type and field names
  * to achieve better performance, Ignite provides metadata for all portable types which
- * can be queried ar runtime via any of the {@link IgniteBinary#metadata(Class)}
+ * can be queried ar runtime via any of the {@link IgniteBinary#type(Class)}
  * methods. Having metadata also allows for proper formatting of {@code PortableObject#toString()} method,
  * even when portable objects are kept in binary format only, which may be necessary for audit reasons.
  * <h1 class="header">Dynamic Structure Changes</h1>
@@ -231,7 +231,8 @@
  * }
  * </pre>
  * Alternatively, if you cannot change class definitions, you can provide custom serialization
- * logic in {@link org.apache.ignite.binary.BinarySerializer} either globally in {@link org.apache.ignite.marshaller.portable.BinaryMarshaller} or
+ * logic in {@link org.apache.ignite.binary.BinarySerializer} either globally in
+ * {@link org.apache.ignite.configuration.BinaryConfiguration} or
  * for a specific type via {@link org.apache.ignite.binary.BinaryTypeConfiguration} instance.
  * <p>
  * Similar to java serialization you can use {@code writeReplace()} and {@code readResolve()} methods.
@@ -251,7 +252,7 @@
  * internally. However, in cases when you want to provide your own ID mapping schema,
  * you can provide your own {@link org.apache.ignite.binary.BinaryIdMapper} implementation.
  * <p>
- * ID-mapper may be provided either globally in {@link org.apache.ignite.marshaller.portable.BinaryMarshaller},
+ * ID-mapper may be provided either globally in {@link org.apache.ignite.configuration.BinaryConfiguration},
  * or for a specific type via {@link org.apache.ignite.binary.BinaryTypeConfiguration} instance.
  * <h1 class="header">Query Indexing</h1>
  * Portable objects can be indexed for querying by specifying index fields in
@@ -323,7 +324,7 @@
      * @return Metadata.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
-    public BinaryType metadata(Class<?> cls) throws BinaryObjectException;
+    public BinaryType type(Class<?> cls) throws BinaryObjectException;
 
     /**
      * Gets metadata for provided class name.
@@ -332,7 +333,7 @@
      * @return Metadata.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
-    public BinaryType metadata(String typeName) throws BinaryObjectException;
+    public BinaryType type(String typeName) throws BinaryObjectException;
 
     /**
      * Gets metadata for provided type ID.
@@ -341,7 +342,7 @@
      * @return Metadata.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
-    public BinaryType metadata(int typeId) throws BinaryObjectException;
+    public BinaryType type(int typeId) throws BinaryObjectException;
 
     /**
      * Gets metadata for all known types.
@@ -349,5 +350,14 @@
      * @return Metadata.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
-    public Collection<BinaryType> metadata() throws BinaryObjectException;
+    public Collection<BinaryType> types() throws BinaryObjectException;
+
+    /**
+     * Create enum object.
+     *
+     * @param typeName Type name.
+     * @param ord Ordinal.
+     * @return Enum object.
+     */
+    public BinaryObject buildEnum(String typeName, int ord);
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
index c9de3f1..3903d02 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
@@ -162,7 +162,8 @@
      * BinaryObject po = prj.get(1);
      * </pre>
      * <p>
-     * Note that this method makes sense only if cache is working in binary mode ({@link org.apache.ignite.marshaller.portable.BinaryMarshaller} is used).
+     * Note that this method makes sense only if cache is working in binary mode
+     * if default marshaller is used.
      * If not, this method is no-op and will return current cache.
      *
      * @return New cache instance for portable objects.
@@ -348,6 +349,19 @@
     public int size(CachePeekMode... peekModes) throws CacheException;
 
     /**
+     * Gets the number of all entries cached across all nodes as a long value. By default, if {@code peekModes} value
+     * isn't defined, only size of primary copies across all nodes will be returned. This behavior is identical to
+     * calling this method with {@link CachePeekMode#PRIMARY} peek mode.
+     * <p>
+     * NOTE: this operation is distributed and will query all participating nodes for their cache sizes.
+     *
+     * @param peekModes Optional peek modes. If not provided, then total cache size is returned.
+     * @return Cache size across all nodes.
+     */
+    @IgniteAsyncSupported
+    public long sizeLong(CachePeekMode... peekModes) throws CacheException;
+
+    /**
      * Gets the number of all entries cached on this node. By default, if {@code peekModes} value isn't defined,
      * only size of primary copies will be returned. This behavior is identical to calling this method with
      * {@link CachePeekMode#PRIMARY} peek mode.
@@ -358,6 +372,16 @@
     public int localSize(CachePeekMode... peekModes);
 
     /**
+     * Gets the number of all entries cached on this node as a long value. By default, if {@code peekModes} value isn't
+     * defined, only size of primary copies will be returned. This behavior is identical to calling this method with
+     * {@link CachePeekMode#PRIMARY} peek mode.
+     *
+     * @param peekModes Optional peek modes. If not provided, then total cache size is returned.
+     * @return Cache size on this node.
+     */
+    public long localSizeLong(CachePeekMode... peekModes);
+
+    /**
      * @param map Map containing keys and entry processors to be applied to values.
      * @param args Additional arguments to pass to the {@link EntryProcessor}.
      * @return The map of {@link EntryProcessorResult}s of the processing per key,
diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryIdMapper.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryIdMapper.java
index 9aebf85..4c31140 100644
--- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryIdMapper.java
+++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryIdMapper.java
@@ -27,7 +27,8 @@
  * actually do collide {@code BinaryIdMapper} allows to override the automatically
  * generated hash code IDs for the type and field names.
  * <p>
- * Binary ID mapper can be configured for all binary objects via {@link org.apache.ignite.configuration.BinaryConfiguration#getIdMapper()} method,
+ * Binary ID mapper can be configured for all binary objects via
+ * {@link org.apache.ignite.configuration.BinaryConfiguration#getIdMapper()} method,
  * or for a specific binary type via {@link BinaryTypeConfiguration#getIdMapper()} method.
  */
 public interface BinaryIdMapper {
diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java
index 2691c7b..f4afd8d 100644
--- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java
+++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryObject.java
@@ -94,19 +94,12 @@
  * <h1 class="header">Binary Type Metadata</h1>
  * Even though Ignite binary protocol only works with hash codes for type and field names
  * to achieve better performance, Ignite provides metadata for all binary types which
- * can be queried ar runtime via any of the {@link org.apache.ignite.IgniteBinary#metadata(Class)}
+ * can be queried ar runtime via any of the {@link org.apache.ignite.IgniteBinary#type(Class)}
  * methods. Having metadata also allows for proper formatting of {@code BinaryObject.toString()} method,
  * even when binary objects are kept in binary format only, which may be necessary for audit reasons.
  */
 public interface BinaryObject extends Serializable, Cloneable {
     /**
-     * Gets binary object type ID.
-     *
-     * @return Type ID.
-     */
-    public int typeId();
-
-    /**
      * Gets type information for this binary object.
      *
      * @return Binary object type information.
@@ -146,4 +139,12 @@
      * @return Copy of this binary object.
      */
     public BinaryObject clone() throws CloneNotSupportedException;
+
+    /**
+     * Get ordinal for this enum object. Use {@link BinaryType#isEnum()} to check if object is of enum type.
+     *
+     * @return Ordinal.
+     * @throws BinaryObjectException If object is not enum.
+     */
+    public int enumOrdinal() throws BinaryObjectException;
 }
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java
index 52bb212..f184a8c 100644
--- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java
+++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryType.java
@@ -21,7 +21,7 @@
 
 /**
  * Binary type meta data. Metadata for binary types can be accessed from any of the
- * {@link org.apache.ignite.IgniteBinary#metadata(String)} methods.
+ * {@link org.apache.ignite.IgniteBinary#type(String)} methods.
  * Having metadata also allows for proper formatting of {@code BinaryObject#toString()} method,
  * even when binary objects are kept in binary format only, which may be necessary for audit reasons.
  */
@@ -34,6 +34,13 @@
     public String typeName();
 
     /**
+     * Gets binary type ID.
+     *
+     * @return Binary type ID.
+     */
+    public int typeId();
+
+    /**
      * Gets collection of all field names for this binary type.
      *
      * @return Collection of all field names for this binary type.
@@ -65,4 +72,11 @@
      * @return Affinity key field name.
      */
     public String affinityKeyFieldName();
+
+    /**
+     * Check whether type represents enum or not.
+     *
+     * @return {@code True} if type is enum.
+     */
+    public boolean isEnum();
 }
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java
index d216866..a694eaf 100644
--- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java
@@ -38,6 +38,9 @@
     /** Serializer. */
     private BinarySerializer serializer;
 
+    /** Enum flag. */
+    private boolean isEnum;
+
     /**
      */
     public BinaryTypeConfiguration() {
@@ -105,6 +108,24 @@
         this.serializer = serializer;
     }
 
+    /**
+     * Gets whether this is enum type.
+     *
+     * @return {@code True} if enum.
+     */
+    public boolean isEnum() {
+        return isEnum;
+    }
+
+    /**
+     * Sets whether this is enum type.
+     *
+     * @param isEnum {@code True} if enum.
+     */
+    public void setEnum(boolean isEnum) {
+        this.isEnum = isEnum;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(BinaryTypeConfiguration.class, this, super.toString());
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheInterceptor.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheInterceptor.java
index 436db6b..103fe57 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/CacheInterceptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheInterceptor.java
@@ -120,4 +120,4 @@
      *      entry is a copy.
      */
     public void onAfterRemove(Cache.Entry<K, V> entry);
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java
index 767b44c..f117847 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.cache;
 
 import java.io.Serializable;
+import java.lang.reflect.Field;
+import org.apache.ignite.cache.affinity.AffinityKeyMapped;
 import org.apache.ignite.internal.util.typedef.internal.S;
 
 /**
@@ -41,6 +43,23 @@
     }
 
     /**
+     * @param keyCls Key class.
+     */
+    public CacheKeyConfiguration(Class keyCls) {
+        typeName = keyCls.getName();
+
+        for (; keyCls != Object.class && keyCls != null; keyCls = keyCls.getSuperclass()) {
+            for (Field f : keyCls.getDeclaredFields()) {
+                if (f.getAnnotation(AffinityKeyMapped.class) != null) {
+                    affKeyFieldName = f.getName();
+
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
      * Creates cache key configuration with given type name and affinity field name.
      *
      * @param typeName Type name.
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java
index 2b7205b..76dea6a 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java
@@ -33,7 +33,9 @@
 
 /**
  * Cache type metadata need for configuration of indexes or automatic persistence.
+ * @deprecated Use {@link org.apache.ignite.cache.QueryEntity} instead.
  */
+@Deprecated
 public class CacheTypeMetadata implements Serializable {
     /** */
     private static final long serialVersionUID = 0L;
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/RendezvousAffinityFunction.java b/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/RendezvousAffinityFunction.java
index 61a21d3..37258d4 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/RendezvousAffinityFunction.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/RendezvousAffinityFunction.java
@@ -480,4 +480,4 @@
                 o1.get2().id().compareTo(o2.get2().id());
         }
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java
index 6dc413b..7617e48 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheAbstractJdbcStore.java
@@ -68,7 +68,7 @@
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.lifecycle.LifecycleAware;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.resources.CacheStoreSessionResource;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.resources.LoggerResource;
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java
index aa013b9..abc4b2e 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStore.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.cache.store.jdbc;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -32,6 +34,7 @@
 import org.apache.ignite.binary.BinaryObjectBuilder;
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.portable.BinaryObjectEx;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.jetbrains.annotations.Nullable;
 
@@ -43,7 +46,7 @@
  */
 public class CacheJdbcPojoStore<K, V> extends CacheAbstractJdbcStore<K, V> {
     /** POJO methods cache. */
-    private volatile Map<String, Map<String, PojoMethodsCache>> pojosMthds = Collections.emptyMap();
+    private volatile Map<String, Map<String, PojoPropertiesCache>> pojosProps = Collections.emptyMap();
 
     /**
      * Get field value from object for use as query parameter.
@@ -80,23 +83,23 @@
     @Nullable private Object extractPojoParameter(@Nullable String cacheName, String typeName, String fldName,
         Object obj) throws CacheException {
         try {
-            Map<String, PojoMethodsCache> cacheMethods = pojosMthds.get(cacheName);
+            Map<String, PojoPropertiesCache> cacheProps = pojosProps.get(cacheName);
 
-            if (cacheMethods == null)
+            if (cacheProps == null)
                 throw new CacheException("Failed to find POJO type metadata for cache: " + U.maskName(cacheName));
 
-            PojoMethodsCache mc = cacheMethods.get(typeName);
+            PojoPropertiesCache ppc = cacheProps.get(typeName);
 
-            if (mc == null)
+            if (ppc == null)
                 throw new CacheException("Failed to find POJO type metadata for type: " + typeName);
 
-            Method getter = mc.getters.get(fldName);
+            ClassProperty prop = ppc.props.get(fldName);
 
-            if (getter == null)
-                throw new CacheLoaderException("Failed to find getter in POJO class [class=" + typeName +
+            if (prop == null)
+                throw new CacheLoaderException("Failed to find property in POJO class [class=" + typeName +
                     ", prop=" + fldName + "]");
 
-            return getter.invoke(obj);
+            return prop.get(obj);
         }
         catch (Exception e) {
             throw new CacheException("Failed to read object of class: " + typeName, e);
@@ -170,26 +173,26 @@
         JdbcTypeField[] flds, Map<String, Integer> loadColIdxs, ResultSet rs)
         throws CacheLoaderException {
 
-        Map<String, PojoMethodsCache> cacheMethods = pojosMthds.get(cacheName);
+        Map<String, PojoPropertiesCache> cacheProps = pojosProps.get(cacheName);
 
-        if (cacheMethods == null)
+        if (cacheProps == null)
             throw new CacheLoaderException("Failed to find POJO types metadata for cache: " + U.maskName(cacheName));
 
-        PojoMethodsCache mc = cacheMethods.get(typeName);
+        PojoPropertiesCache ppc = cacheProps.get(typeName);
 
-        if (mc == null)
+        if (ppc == null)
             throw new CacheLoaderException("Failed to find POJO type metadata for type: " + typeName);
 
         try {
-            Object obj = mc.ctor.newInstance();
+            Object obj = ppc.ctor.newInstance();
 
             for (JdbcTypeField fld : flds) {
                 String fldJavaName = fld.getJavaFieldName();
 
-                Method setter = mc.setters.get(fldJavaName);
+                ClassProperty prop = ppc.props.get(fldJavaName);
 
-                if (setter == null)
-                    throw new IllegalStateException("Failed to find setter in POJO class [type=" + typeName +
+                if (prop == null)
+                    throw new IllegalStateException("Failed to find property in POJO class [type=" + typeName +
                         ", prop=" + fldJavaName + "]");
 
                 String fldDbName = fld.getDatabaseFieldName();
@@ -200,7 +203,7 @@
                     Object colVal = getColumnValue(rs, colIdx, fld.getJavaFieldType());
 
                     try {
-                        setter.invoke(obj, colVal);
+                        prop.set(obj, colVal);
                     }
                     catch (Exception e) {
                         throw new CacheLoaderException("Failed to set property in POJO class [type=" + typeName +
@@ -270,7 +273,7 @@
      */
     @Override protected Object typeIdForObject(Object obj) throws CacheException {
         if (obj instanceof BinaryObject)
-            return ((BinaryObject)obj).typeId();
+            return ((BinaryObjectEx)obj).typeId();
 
         return obj.getClass();
     }
@@ -297,7 +300,7 @@
      */
     @Override protected void prepareBuilders(@Nullable String cacheName, Collection<JdbcType> types)
         throws CacheException {
-        Map<String, PojoMethodsCache> pojoMethods = U.newHashMap(types.size() * 2);
+        Map<String, PojoPropertiesCache> pojoProps = U.newHashMap(types.size() * 2);
 
         for (JdbcType type : types) {
             String keyTypeName = type.getKeyType();
@@ -305,11 +308,11 @@
             TypeKind keyKind = kindForName(keyTypeName);
 
             if (keyKind == TypeKind.POJO) {
-                if (pojoMethods.containsKey(keyTypeName))
+                if (pojoProps.containsKey(keyTypeName))
                     throw new CacheException("Found duplicate key type [cache=" + U.maskName(cacheName) +
                         ", keyType=" + keyTypeName + "]");
 
-                pojoMethods.put(keyTypeName, new PojoMethodsCache(keyTypeName, type.getKeyFields()));
+                pojoProps.put(keyTypeName, new PojoPropertiesCache(keyTypeName, type.getKeyFields()));
             }
 
             String valTypeName = type.getValueType();
@@ -317,42 +320,99 @@
             TypeKind valKind = kindForName(valTypeName);
 
             if (valKind == TypeKind.POJO)
-                pojoMethods.put(valTypeName, new PojoMethodsCache(valTypeName, type.getValueFields()));
+                pojoProps.put(valTypeName, new PojoPropertiesCache(valTypeName, type.getValueFields()));
         }
 
-        if (!pojoMethods.isEmpty()) {
-            Map<String, Map<String, PojoMethodsCache>> newPojosMethods = new HashMap<>(pojosMthds);
+        if (!pojoProps.isEmpty()) {
+            Map<String, Map<String, PojoPropertiesCache>> newPojosProps = new HashMap<>(pojosProps);
 
-            newPojosMethods.put(cacheName, pojoMethods);
+            newPojosProps.put(cacheName, pojoProps);
 
-            pojosMthds = newPojosMethods;
+            pojosProps = newPojosProps;
+        }
+    }
+
+    /**
+     * Description of type property.
+     */
+    private static class ClassProperty {
+        /** */
+        private final Method getter;
+        /** */
+        private final Method setter;
+        /** */
+        private final Field field;
+
+        /**
+         * Property descriptor constructor.
+         *
+         * @param getter Property getter.
+         * @param setter Property setter.
+         * @param field Property field.
+         */
+        private ClassProperty(Method getter, Method setter, Field field) {
+            this.getter = getter;
+            this.setter = setter;
+            this.field = field;
+        }
+
+        /**
+         * Get property value.
+         *
+         * @param obj Object to get property value from.
+         * @return Property value.
+         * @throws IllegalAccessException
+         * @throws InvocationTargetException
+         */
+        private Object get(Object obj) throws IllegalAccessException, InvocationTargetException {
+            if (getter != null)
+                return getter.invoke(obj);
+
+            if (field != null)
+                return field.get(obj);
+
+            throw new IllegalAccessException("Failed to get value from property. Getter and field was not initialized.");
+        }
+
+        /**
+         * Set property value.
+         *
+         * @param obj Object to set property value to.
+         * @param val New property value to set.
+         * @throws IllegalAccessException
+         * @throws InvocationTargetException
+         */
+        private void set(Object obj, Object val) throws IllegalAccessException, InvocationTargetException {
+            if (setter != null)
+                setter.invoke(obj, val);
+            else if (field != null)
+                field.set(obj, val);
+            else
+                throw new IllegalAccessException("Failed to set new value from property.  Setter and field was not initialized.");
         }
     }
 
     /**
      * POJO methods cache.
      */
-    private static class PojoMethodsCache {
+    private static class PojoPropertiesCache {
         /** POJO class. */
         private final Class<?> cls;
 
         /** Constructor for POJO object. */
         private Constructor ctor;
 
-        /** Cached setters for POJO object. */
-        private Map<String, Method> getters;
-
-        /** Cached getters for POJO object. */
-        private Map<String, Method> setters;
+        /** Cached properties for POJO object. */
+        private Map<String, ClassProperty> props;
 
         /**
          * POJO methods cache.
          *
          * @param clsName Class name.
-         * @param fields Fields.
+         * @param jdbcFlds Type fields.
          * @throws CacheException If failed to construct type cache.
          */
-        private PojoMethodsCache(String clsName, JdbcTypeField[] fields) throws CacheException {
+        private PojoPropertiesCache(String clsName, JdbcTypeField[] jdbcFlds) throws CacheException {
             try {
                 cls = Class.forName(clsName);
 
@@ -368,33 +428,35 @@
                 throw new CacheException("Failed to find default constructor for class: " + clsName, e);
             }
 
-            setters = U.newHashMap(fields.length);
+            props = U.newHashMap(jdbcFlds.length);
 
-            getters = U.newHashMap(fields.length);
+            for (JdbcTypeField jdbcFld : jdbcFlds) {
+                String fldName = jdbcFld.getJavaFieldName();
+                String mthName = capitalFirst(fldName);
 
-            for (JdbcTypeField field : fields) {
-                String prop = capitalFirst(field.getJavaFieldName());
+                Method getter = methodByName(cls, "get" + mthName);
 
-                try {
-                    getters.put(field.getJavaFieldName(), cls.getMethod("get" + prop));
-                }
-                catch (NoSuchMethodException ignored) {
+                if (getter == null)
+                    getter = methodByName(cls, "is" + mthName);
+
+                if (getter == null)
+                    getter = methodByName(cls, fldName);
+
+                Method setter = methodByName(cls, "set" + mthName, jdbcFld.getJavaFieldType());
+
+                if (setter == null)
+                    setter = methodByName(cls, fldName, jdbcFld.getJavaFieldType());
+
+                if (getter != null && setter != null)
+                    props.put(fldName, new ClassProperty(getter, setter, null));
+                else
                     try {
-                        getters.put(field.getJavaFieldName(), cls.getMethod("is" + prop));
+                        props.put(fldName, new ClassProperty(null, null, cls.getDeclaredField(fldName)));
                     }
-                    catch (NoSuchMethodException e) {
-                        throw new CacheException("Failed to find getter in POJO class [class=" + clsName +
-                            ", prop=" + field.getJavaFieldName() + "]", e);
+                    catch (NoSuchFieldException ignored) {
+                        throw new CacheException("Failed to find property in POJO class [class=" + clsName +
+                            ", prop=" + fldName + "]");
                     }
-                }
-
-                try {
-                    setters.put(field.getJavaFieldName(), cls.getMethod("set" + prop, field.getJavaFieldType()));
-                }
-                catch (NoSuchMethodException e) {
-                    throw new CacheException("Failed to find setter in POJO class [class=" + clsName +
-                        ", prop=" + field.getJavaFieldName() + "]", e);
-                }
             }
         }
 
@@ -408,5 +470,22 @@
             return str == null ? null :
                 str.isEmpty() ? "" : Character.toUpperCase(str.charAt(0)) + str.substring(1);
         }
+
+        /**
+         * Get method by name.
+         *
+         * @param cls Class to take method from.
+         * @param name Method name.
+         * @param paramTypes Method parameters types.
+         * @return Method or {@code null} if method not found.
+         */
+        private Method methodByName(Class<?> cls, String name, Class<?>... paramTypes) {
+            try {
+                return cls.getMethod(name, paramTypes);
+            }
+            catch (NoSuchMethodException ignored) {
+                return null;
+            }
+        }
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
index e87346f..034d20d 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
@@ -45,6 +45,7 @@
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheEntryProcessor;
 import org.apache.ignite.cache.CacheInterceptor;
+import org.apache.ignite.cache.CacheKeyConfiguration;
 import org.apache.ignite.cache.CacheMemoryMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CacheRebalanceMode;
@@ -208,7 +209,7 @@
 
     /** Default value for keep binary in store behavior .*/
     @SuppressWarnings({"UnnecessaryBoxing", "BooleanConstructorCall"})
-    public static final Boolean DFLT_KEEP_BINARY_IN_STORE = new Boolean(true);
+    public static final Boolean DFLT_KEEP_BINARY_IN_STORE = new Boolean(false);
 
     /** Default threshold for concurrent loading of keys from {@link CacheStore}. */
     public static final int DFLT_CONCURRENT_LOAD_ALL_THRESHOLD = 5;
@@ -373,6 +374,9 @@
     /** */
     private int sqlOnheapRowCacheSize = DFLT_SQL_ONHEAP_ROW_CACHE_SIZE;
 
+    /** */
+    private boolean snapshotableIdx;
+
     /** Copy on read flag. */
     private boolean cpOnRead = DFLT_COPY_ON_READ;
 
@@ -463,6 +467,7 @@
         rebalancePoolSize = cc.getRebalanceThreadPoolSize();
         rebalanceTimeout = cc.getRebalanceTimeout();
         rebalanceThrottle = cc.getRebalanceThrottle();
+        snapshotableIdx = cc.isSnapshotableIndex();
         sqlEscapeAll = cc.isSqlEscapeAll();
         sqlFuncCls = cc.getSqlFunctionClasses();
         sqlOnheapRowCacheSize = cc.getSqlOnheapRowCacheSize();
@@ -887,8 +892,7 @@
     /**
      * Flag indicating that {@link CacheStore} implementation
      * is working with binary objects instead of Java objects.
-     * Default value of this flag is {@link #DFLT_KEEP_BINARY_IN_STORE},
-     * because this is recommended behavior from performance standpoint.
+     * Default value of this flag is {@link #DFLT_KEEP_BINARY_IN_STORE}.
      * <p>
      * If set to {@code false}, Ignite will deserialize keys and
      * values stored in binary format before they are passed
@@ -1900,6 +1904,32 @@
     }
 
     /**
+     * Gets flag indicating whether SQL indexes should support snapshots.
+     *
+     * @return {@code True} if SQL indexes should support snapshots.
+     */
+    public boolean isSnapshotableIndex() {
+        return snapshotableIdx;
+    }
+
+    /**
+     * Sets flag indicating whether SQL indexes should support snapshots.
+     * <p>
+     * Default value is {@code false}.
+     * <p>
+     * <b>Note</b> that this flag is ignored if indexes are stored in offheap memory,
+     * for offheap indexes snapshots are always enabled.
+     *
+     * @param snapshotableIdx {@code True} if SQL indexes should support snapshots.
+     * @return {@code this} for chaining.
+     */
+    public CacheConfiguration<K, V> setSnapshotableIndex(boolean snapshotableIdx) {
+        this.snapshotableIdx = snapshotableIdx;
+
+        return this;
+    }
+
+    /**
      * Gets array of cache plugin configurations.
      *
      * @return Cache plugin configurations.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java
index 1869d2e..be35ba4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java
@@ -125,6 +125,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean keepBinary() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
     @Override public String cacheName() {
         throw new IllegalStateException();
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java
index 6b51107..2edfda5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridMessageListenHandler.java
@@ -98,6 +98,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean keepBinary() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
     @Override public String cacheName() {
         throw new IllegalStateException();
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 082ffa5..87ccf93 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -53,21 +53,21 @@
 import org.apache.ignite.IgniteAtomicReference;
 import org.apache.ignite.IgniteAtomicSequence;
 import org.apache.ignite.IgniteAtomicStamped;
+import org.apache.ignite.IgniteBinary;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteClientDisconnectedException;
 import org.apache.ignite.IgniteCompute;
 import org.apache.ignite.IgniteCountDownLatch;
-import org.apache.ignite.IgniteSemaphore;
 import org.apache.ignite.IgniteDataStreamer;
 import org.apache.ignite.IgniteEvents;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteFileSystem;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.IgniteMessaging;
-import org.apache.ignite.IgniteBinary;
 import org.apache.ignite.IgniteQueue;
 import org.apache.ignite.IgniteScheduler;
+import org.apache.ignite.IgniteSemaphore;
 import org.apache.ignite.IgniteServices;
 import org.apache.ignite.IgniteSet;
 import org.apache.ignite.IgniteSystemProperties;
@@ -96,6 +96,8 @@
 import org.apache.ignite.internal.managers.indexing.GridIndexingManager;
 import org.apache.ignite.internal.managers.loadbalancer.GridLoadBalancerManager;
 import org.apache.ignite.internal.managers.swapspace.GridSwapSpaceManager;
+import org.apache.ignite.internal.portable.BinaryEnumCache;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.internal.processors.GridProcessor;
 import org.apache.ignite.internal.processors.affinity.GridAffinityProcessor;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
@@ -133,7 +135,6 @@
 import org.apache.ignite.internal.processors.session.GridTaskSessionProcessor;
 import org.apache.ignite.internal.processors.task.GridTaskProcessor;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
-import org.apache.ignite.internal.portable.BinaryEnumCache;
 import org.apache.ignite.internal.util.GridTimerTask;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -158,7 +159,6 @@
 import org.apache.ignite.lifecycle.LifecycleEventType;
 import org.apache.ignite.marshaller.MarshallerExclusions;
 import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.mxbean.ClusterLocalNodeMetricsMXBean;
 import org.apache.ignite.mxbean.IgniteMXBean;
 import org.apache.ignite.mxbean.ThreadPoolMXBean;
@@ -1192,9 +1192,8 @@
         if (cfg.getIncludeEventTypes() != null && cfg.getIncludeEventTypes().length != 0)
             perf.add("Disable grid events (remove 'includeEventTypes' from configuration)");
 
-        if (OptimizedMarshaller.available() && !(cfg.getMarshaller() instanceof OptimizedMarshaller))
-            perf.add("Enable optimized marshaller (set 'marshaller' to " +
-                OptimizedMarshaller.class.getSimpleName() + ')');
+        if (BinaryMarshaller.available() && (cfg.getMarshaller() != null && !(cfg.getMarshaller() instanceof BinaryMarshaller)))
+            perf.add("Use default binary marshaller (do not set 'marshaller' explicitly)");
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
index 7d2b2dc..889b25c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
@@ -61,6 +61,7 @@
 import org.apache.ignite.configuration.FileSystemConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.internal.processors.resource.GridSpringResourceContext;
 import org.apache.ignite.internal.util.GridConcurrentHashSet;
 import org.apache.ignite.internal.util.IgniteUtils;
@@ -76,7 +77,6 @@
 import org.apache.ignite.logger.java.JavaLogger;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.marshaller.jdk.JdkMarshaller;
-import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
 import org.apache.ignite.mxbean.IgnitionMXBean;
 import org.apache.ignite.plugin.segmentation.SegmentationPolicy;
 import org.apache.ignite.resources.SpringApplicationContextResource;
@@ -1187,8 +1187,8 @@
         Ignite res;
 
         if (grid == null || (res = grid.grid()) == null)
-            throw new IgniteIllegalStateException("Grid instance was not properly started " +
-                "or was already stopped: " + name);
+            throw new IgniteIllegalStateException("Ignite instance with provided name doesn't exist. " +
+                "Did you call Ignition.start(..) to start an Ignite instance? [name=" + name + ']');
 
         return res;
     }
@@ -1205,7 +1205,8 @@
         IgniteKernal res;
 
         if (grid == null || (res = grid.gridx()) == null)
-            throw new IllegalStateException("Grid instance was not properly started or was already stopped: " + name);
+            throw new IgniteIllegalStateException("Ignite instance with provided name doesn't exist. " +
+                "Did you call Ignition.start(..) to start an Ignite instance? [name=" + name + ']');
 
         return res;
     }
@@ -1793,7 +1794,7 @@
             Marshaller marsh = myCfg.getMarshaller();
 
             if (marsh == null) {
-                if (!OptimizedMarshaller.available()) {
+                if (!BinaryMarshaller.available()) {
                     U.warn(log, "OptimizedMarshaller is not supported on this JVM " +
                         "(only recent 1.6 and 1.7 versions HotSpot VMs are supported). " +
                         "To enable fast marshalling upgrade to recent 1.6 or 1.7 HotSpot VM release. " +
@@ -1804,7 +1805,7 @@
                     marsh = new JdkMarshaller();
                 }
                 else
-                    marsh = new OptimizedMarshaller();
+                    marsh = new BinaryMarshaller();
             }
 
             myCfg.setMarshaller(marsh);
@@ -2388,4 +2389,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/main/java/org/apache/ignite/internal/NodeStoppingException.java
similarity index 69%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/main/java/org/apache/ignite/internal/NodeStoppingException.java
index 6548210..164983a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/NodeStoppingException.java
@@ -15,18 +15,21 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.internal;
+
+import org.apache.ignite.IgniteCheckedException;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class NodeStoppingException extends IgniteCheckedException {
+    /** */
+    private static final long serialVersionUID = 0L;
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+    /**
+     * @param msg Exception message.
+     */
+    public NodeStoppingException(String msg) {
+        super(msg);
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java
index ea82d7f..a8557cc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java
@@ -46,8 +46,6 @@
 import org.apache.ignite.internal.GridTopic;
 import org.apache.ignite.internal.IgniteComponentType;
 import org.apache.ignite.internal.IgniteDeploymentCheckedException;
-import org.apache.ignite.internal.IgniteKernal;
-import org.apache.ignite.internal.IgnitionEx;
 import org.apache.ignite.internal.direct.DirectMessageReader;
 import org.apache.ignite.internal.direct.DirectMessageWriter;
 import org.apache.ignite.internal.managers.GridManagerAdapter;
@@ -103,9 +101,6 @@
  * Grid communication manager.
  */
 public class GridIoManager extends GridManagerAdapter<CommunicationSpi<Serializable>> {
-    /** */
-    public static volatile boolean TURBO_DEBUG_MODE;
-
     /** Empty array of message factories. */
     public static final MessageFactory[] EMPTY = {};
 
@@ -775,7 +770,7 @@
     private void processRegularMessage(
         final UUID nodeId,
         final GridIoMessage msg,
-        byte plc,
+        final byte plc,
         final IgniteRunnable msgC
     ) throws IgniteCheckedException {
         Runnable c = new Runnable() {
@@ -956,7 +951,7 @@
 
         if (msgC == null) {
             // Message from local node can be processed in sync manner.
-            assert locNodeId.equals(nodeId) || TURBO_DEBUG_MODE;
+            assert locNodeId.equals(nodeId);
 
             unwindMessageSet(set, lsnr);
 
@@ -1089,85 +1084,6 @@
     }
 
     /**
-     * This method can be used for debugging tricky concurrency issues
-     * with multi-nodes in single JVM.
-     * <p>
-     * This method eliminates network between nodes started in single JVM
-     * when {@link #TURBO_DEBUG_MODE} is set to {@code true}.
-     * <p>
-     * How to use it:
-     * <ol>
-     *     <li>Replace {@link #send(ClusterNode, Object, int, Message, byte, boolean, long, boolean, IgniteInClosure)}
-     *          with this method.</li>
-     *     <li>Start all grids for your test, then set {@link #TURBO_DEBUG_MODE} to {@code true}.</li>
-     *     <li>Perform test operations on the topology. No network will be there.</li>
-     *     <li>DO NOT turn on turbo debug before all grids started. This will cause deadlocks.</li>
-     * </ol>
-     *
-     * @param node Destination node.
-     * @param topic Topic to send the message to.
-     * @param topicOrd GridTopic enumeration ordinal.
-     * @param msg Message to send.
-     * @param plc Type of processing.
-     * @param ordered Ordered flag.
-     * @param timeout Timeout.
-     * @param skipOnTimeout Whether message can be skipped on timeout.
-     * @throws IgniteCheckedException Thrown in case of any errors.
-     */
-    private void sendTurboDebug(
-        ClusterNode node,
-        Object topic,
-        int topicOrd,
-        Message msg,
-        byte plc,
-        boolean ordered,
-        long timeout,
-        boolean skipOnTimeout
-    ) throws IgniteCheckedException {
-        assert node != null;
-        assert topic != null;
-        assert msg != null;
-
-        GridIoMessage ioMsg = new GridIoMessage(plc, topic, topicOrd, msg, ordered, timeout, skipOnTimeout);
-
-        IgniteKernal rmt;
-
-        if (locNodeId.equals(node.id())) {
-            assert plc != P2P_POOL;
-
-            CommunicationListener commLsnr = this.commLsnr;
-
-            if (commLsnr == null)
-                throw new IgniteCheckedException("Trying to send message when grid is not fully started.");
-
-            if (ordered)
-                processOrderedMessage(locNodeId, ioMsg, plc, null);
-            else
-                processRegularMessage0(ioMsg, locNodeId);
-        }
-        else if (TURBO_DEBUG_MODE && (rmt = IgnitionEx.gridxx(locNodeId)) != null) {
-            if (ioMsg.isOrdered())
-                rmt.context().io().processOrderedMessage(locNodeId, ioMsg, ioMsg.policy(), null);
-            else
-                rmt.context().io().processRegularMessage0(ioMsg, locNodeId);
-        }
-        else {
-            if (topicOrd < 0)
-                ioMsg.topicBytes(marsh.marshal(topic));
-
-            try {
-                getSpi().sendMessage(node, ioMsg);
-            }
-            catch (IgniteSpiException e) {
-                throw new IgniteCheckedException("Failed to send message (node may have left the grid or " +
-                    "TCP connection cannot be established due to firewall issues) " +
-                    "[node=" + node + ", topic=" + topic +
-                    ", msg=" + msg + ", policy=" + plc + ']', e);
-            }
-        }
-    }
-
-    /**
      * @param nodeId Id of destination node.
      * @param topic Topic to send the message to.
      * @param msg Message to send.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
index 02bd5ec..c9b8e27 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
@@ -31,6 +31,7 @@
 import org.apache.ignite.internal.managers.deployment.GridDeploymentRequest;
 import org.apache.ignite.internal.managers.deployment.GridDeploymentResponse;
 import org.apache.ignite.internal.managers.eventstorage.GridEventStorageMessage;
+import org.apache.ignite.internal.portable.BinaryEnumObjectImpl;
 import org.apache.ignite.internal.portable.BinaryObjectImpl;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection;
@@ -714,7 +715,12 @@
 
                 break;
 
-            // [-3..118] - this
+            case 119:
+                msg = new BinaryEnumObjectImpl();
+
+                break;
+
+            // [-3..119] - this
             // [120..123] - DR
             // [-4..-22] - SQL
             default:
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index 4880338..92d66d7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -43,6 +43,7 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
@@ -175,14 +176,6 @@
         }
     };
 
-    /** Disco history entries comparator. */
-    private static final Comparator<Map.Entry<AffinityTopologyVersion, DiscoCache>> histCmp =
-        new Comparator<Map.Entry<AffinityTopologyVersion, DiscoCache>>() {
-            @Override public int compare(Map.Entry<AffinityTopologyVersion, DiscoCache> o1, Map.Entry<AffinityTopologyVersion, DiscoCache> o2) {
-                return o1.getKey().compareTo(o2.getKey());
-            }
-        };
-
     /** Discovery event worker. */
     private final DiscoveryWorker discoWrk = new DiscoveryWorker();
 
@@ -208,7 +201,7 @@
     private final AtomicBoolean lastSegChkRes = new AtomicBoolean(true);
 
     /** Topology cache history. */
-    private final Map<AffinityTopologyVersion, DiscoCache> discoCacheHist =
+    private final ConcurrentNavigableMap<AffinityTopologyVersion, DiscoCache> discoCacheHist =
         new GridBoundedConcurrentOrderedMap<>(DISCOVERY_HISTORY_SIZE);
 
     /** Topology snapshots history. */
@@ -1638,10 +1631,12 @@
 
         if (cache == null) {
             // Find the eldest acceptable discovery cache.
-            Map.Entry<AffinityTopologyVersion, DiscoCache> eldest = Collections.min(discoCacheHist.entrySet(), histCmp);
+            Map.Entry<AffinityTopologyVersion, DiscoCache> eldest = discoCacheHist.firstEntry();
 
-            if (topVer.compareTo(eldest.getKey()) < 0)
-                cache = eldest.getValue();
+            if (eldest != null) {
+                if (topVer.compareTo(eldest.getKey()) < 0)
+                    cache = eldest.getValue();
+            }
         }
 
         if (cache == null) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumObjectImpl.java
new file mode 100644
index 0000000..467d767
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryEnumObjectImpl.java
@@ -0,0 +1,311 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.internal.GridDirectTransient;
+import org.apache.ignite.internal.processors.cache.CacheObject;
+import org.apache.ignite.internal.processors.cache.CacheObjectContext;
+import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
+import org.apache.ignite.internal.util.typedef.internal.SB;
+import org.apache.ignite.plugin.extensions.communication.MessageReader;
+import org.apache.ignite.plugin.extensions.communication.MessageWriter;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+
+/**
+ * Binary enum object.
+ */
+public class BinaryEnumObjectImpl implements BinaryObjectEx, Externalizable, CacheObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Context. */
+    @GridDirectTransient
+    private PortableContext ctx;
+
+    /** Type ID. */
+    private int typeId;
+
+    /** Raw data. */
+    private String clsName;
+
+    /** Ordinal. */
+    private int ord;
+
+    /**
+     * {@link Externalizable} support.
+     */
+    public BinaryEnumObjectImpl() {
+        // No-op.
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Context.
+     * @param typeId Type ID.
+     * @param clsName Class name.
+     * @param ord Ordinal.
+     */
+    public BinaryEnumObjectImpl(PortableContext ctx, int typeId, @Nullable String clsName, int ord) {
+        assert ctx != null;
+
+        this.ctx = ctx;
+        this.typeId = typeId;
+        this.clsName = clsName;
+        this.ord = ord;
+    }
+
+    /**
+     * @return Class name.
+     */
+    @Nullable public String className() {
+        return clsName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int typeId() {
+        return typeId;
+    }
+
+    /** {@inheritDoc} */
+    @Override public BinaryType type() throws BinaryObjectException {
+        return ctx.metadata(typeId());
+    }
+
+    /** {@inheritDoc} */
+    @Override public <F> F field(String fieldName) throws BinaryObjectException {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean hasField(String fieldName) {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public <T> T deserialize() throws BinaryObjectException {
+        Class cls = PortableUtils.resolveClass(ctx, typeId, clsName, null, true);
+
+        return BinaryEnumCache.get(cls, ord);
+    }
+
+    /** {@inheritDoc} */
+    @Override public BinaryObject clone() throws CloneNotSupportedException {
+        return (BinaryObject)super.clone();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int enumOrdinal() throws BinaryObjectException {
+        return ord;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return 31 * typeId + ord;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object obj) {
+        if (obj != null && (obj instanceof BinaryEnumObjectImpl)) {
+            BinaryEnumObjectImpl other = (BinaryEnumObjectImpl)obj;
+
+            return typeId == other.typeId && ord == other.ord;
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        // 1. Try deserializing the object.
+        try {
+            Object val = deserialize();
+
+            return new SB().a(val).toString();
+        }
+        catch (Exception e) {
+            // No-op.
+        }
+
+        // 2. Try getting meta.
+        BinaryType type;
+
+        try {
+            type = type();
+        }
+        catch (Exception e) {
+            type = null;
+        }
+
+        if (type != null) {
+            return type.typeName() + "[ordinal=" + ord  + ']';
+        }
+        else {
+            if (typeId == GridPortableMarshaller.UNREGISTERED_TYPE_ID)
+                return "BinaryEnum[clsName=" + clsName + ", ordinal=" + ord + ']';
+            else
+                return "BinaryEnum[typeId=" + typeId + ", ordinal=" + ord + ']';
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(ctx);
+
+        out.writeInt(typeId);
+        out.writeObject(clsName);
+        out.writeInt(ord);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        ctx = (PortableContext)in.readObject();
+
+        typeId = in.readInt();
+        clsName = (String)in.readObject();
+        ord = in.readInt();
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean cpy) {
+        return deserialize();
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] valueBytes(CacheObjectContext cacheCtx) throws IgniteCheckedException {
+        return ctx.marshaller().marshal(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte cacheObjectType() {
+        return TYPE_BINARY;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isPlatformType() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader ldr) throws IgniteCheckedException {
+        this.ctx = ((CacheObjectBinaryProcessorImpl)ctx.processor()).portableContext();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(CacheObjectContext ctx) throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte directType() {
+        return 119;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte fieldsCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+        writer.setBuffer(buf);
+
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(directType(), fieldsCount()))
+                return false;
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 0:
+                if (!writer.writeString("clsName", clsName))
+                    return false;
+
+                writer.incrementState();
+
+            case 1:
+                if (!writer.writeInt("ord", ord))
+                    return false;
+
+                writer.incrementState();
+
+            case 2:
+                if (!writer.writeInt("typeId", typeId))
+                    return false;
+
+                writer.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+        reader.setBuffer(buf);
+
+        if (!reader.beforeMessageRead())
+            return false;
+
+        switch (reader.state()) {
+            case 0:
+                clsName = reader.readString("clsName");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 1:
+                ord = reader.readInt("ord");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 2:
+                typeId = reader.readInt("typeId");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+        }
+
+        return reader.afterMessageRead(BinaryEnumObjectImpl.class);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java
index 810c820..b471fbe 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java
@@ -66,7 +66,7 @@
 
     /** {@inheritDoc} */
     @Override public boolean exists(BinaryObject obj) {
-        BinaryObjectEx obj0 = (BinaryObjectEx)obj;
+        BinaryObjectExImpl obj0 = (BinaryObjectExImpl)obj;
 
         return fieldOrder(obj0) != PortableSchema.ORDER_NOT_FOUND;
     }
@@ -74,7 +74,7 @@
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Override public <T> T value(BinaryObject obj) {
-        BinaryObjectEx obj0 = (BinaryObjectEx)obj;
+        BinaryObjectExImpl obj0 = (BinaryObjectExImpl)obj;
 
         int order = fieldOrder(obj0);
 
@@ -87,7 +87,7 @@
      * @param obj Object.
      * @return Field offset.
      */
-    private int fieldOrder(BinaryObjectEx obj) {
+    private int fieldOrder(BinaryObjectExImpl obj) {
         if (typeId != obj.typeId()) {
             throw new BinaryObjectException("Failed to get field because type ID of passed object differs" +
                 " from type ID this " + BinaryField.class.getSimpleName() + " belongs to [expected=" + typeId +
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/portable/BinaryMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMarshaller.java
similarity index 70%
rename from modules/core/src/main/java/org/apache/ignite/marshaller/portable/BinaryMarshaller.java
rename to modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMarshaller.java
index 455c83e..bfaae74 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/portable/BinaryMarshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMarshaller.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.marshaller.portable;
+package org.apache.ignite.internal.portable;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -24,56 +24,52 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.internal.portable.GridPortableMarshaller;
-import org.apache.ignite.internal.portable.PortableContext;
+import org.apache.ignite.internal.util.GridUnsafe;
 import org.apache.ignite.marshaller.AbstractMarshaller;
 import org.apache.ignite.marshaller.MarshallerContext;
 import org.jetbrains.annotations.Nullable;
+import sun.misc.Unsafe;
 
 /**
  * Implementation of {@link org.apache.ignite.marshaller.Marshaller} that lets to serialize and deserialize all objects
- * in the portable format.
- * <p>
- * {@code PortableMarshaller} is tested only on Java HotSpot VM on other VMs it could yield unexpected results.
- * <p>
- * <h1 class="header">Configuration</h1>
- * <h2 class="header">Mandatory</h2>
- * This marshaller has no mandatory configuration parameters.
- * <h2 class="header">Java Example</h2>
- * <pre name="code" class="java">
- * PortableMarshaller marshaller = new PortableMarshaller();
- *
- * IgniteConfiguration cfg = new IgniteConfiguration();
- *
- * // Override marshaller.
- * cfg.setMarshaller(marshaller);
- *
- * // Starts grid.
- * G.start(cfg);
- * </pre>
- * <h2 class="header">Spring Example</h2>
- * PortableMarshaller can be configured from Spring XML configuration file:
- * <pre name="code" class="xml">
- * &lt;bean id="grid.custom.cfg" class="org.apache.ignite.configuration.IgniteConfiguration" singleton="true"&gt;
- *     ...
- *     &lt;property name="marshaller"&gt;
- *         &lt;bean class="org.apache.ignite.marshaller.portable.PortableMarshaller"&gt;
- *            ...
- *         &lt;/bean&gt;
- *     &lt;/property&gt;
- *     ...
- * &lt;/bean&gt;
- * </pre>
- * <p>
- * <img src="http://ignite.apache.org/images/spring-small.png">
- * <br>
- * For information about Spring framework visit <a href="http://www.springframework.org/">www.springframework.org</a>
+ * in the binary format.
  */
 public class BinaryMarshaller extends AbstractMarshaller {
     /** */
     private GridPortableMarshaller impl;
 
     /**
+     * Checks whether {@code BinaryMarshaller} is able to work on the current JVM.
+     * <p>
+     * As long as {@code BinaryMarshaller} uses JVM-private API, which is not guaranteed
+     * to be available on all JVM, this method should be called to ensure marshaller could work properly.
+     * <p>
+     * Result of this method is automatically checked in constructor.
+     *
+     * @return {@code true} if {@code BinaryMarshaller} can work on the current JVM or
+     *      {@code false} if it can't.
+     */
+    @SuppressWarnings({"TypeParameterExtendsFinalClass", "ErrorNotRethrown"})
+    public static boolean available() {
+        try {
+            Unsafe unsafe = GridUnsafe.unsafe();
+
+            Class<? extends Unsafe> unsafeCls = unsafe.getClass();
+
+            unsafeCls.getMethod("allocateInstance", Class.class);
+            unsafeCls.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+
+            return true;
+        }
+        catch (Exception ignored) {
+            return false;
+        }
+        catch (NoClassDefFoundError ignored) {
+            return false;
+        }
+    }
+
+    /**
      * Returns currently set {@link MarshallerContext}.
      *
      * @return Marshaller context.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadata.java
index a464d6e..8ba2e23 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetadata.java
@@ -52,6 +52,9 @@
     /** Schemas associated with type. */
     private Collection<PortableSchema> schemas;
 
+    /** Whether this is enum type. */
+    private boolean isEnum;
+
     /**
      * For {@link Externalizable}.
      */
@@ -67,9 +70,10 @@
      * @param fields Fields map.
      * @param affKeyFieldName Affinity key field name.
      * @param schemas Schemas.
+     * @param isEnum Enum flag.
      */
     public BinaryMetadata(int typeId, String typeName, @Nullable Map<String, Integer> fields,
-        @Nullable String affKeyFieldName, @Nullable Collection<PortableSchema> schemas) {
+        @Nullable String affKeyFieldName, @Nullable Collection<PortableSchema> schemas, boolean isEnum) {
         assert typeName != null;
 
         this.typeId = typeId;
@@ -77,6 +81,7 @@
         this.fields = fields;
         this.affKeyFieldName = affKeyFieldName;
         this.schemas = schemas;
+        this.isEnum = isEnum;
     }
 
     /**
@@ -132,6 +137,13 @@
     }
 
     /**
+     * @return {@code True} if this is enum type.
+     */
+    public boolean isEnum() {
+        return isEnum;
+    }
+
+    /**
      * Wrap metadata into binary type.
      *
      * @param ctx Portable context.
@@ -148,6 +160,7 @@
         U.writeMap(out, fields);
         U.writeString(out, affKeyFieldName);
         U.writeCollection(out, schemas);
+        out.writeBoolean(isEnum);
     }
 
     /** {@inheritDoc} */
@@ -157,6 +170,7 @@
         fields = U.readMap(in);
         affKeyFieldName = U.readString(in);
         schemas = U.readCollection(in);
+        isEnum = in.readBoolean();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
index 597fad5..acc8e4b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectEx.java
@@ -17,229 +17,14 @@
 
 package org.apache.ignite.internal.portable;
 
-import java.math.BigDecimal;
-import java.util.Arrays;
-import java.util.IdentityHashMap;
-import org.apache.ignite.IgniteException;
-import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
-import org.apache.ignite.internal.util.typedef.internal.SB;
-import org.apache.ignite.binary.BinaryObjectException;
-import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.binary.BinaryObject;
-import org.jetbrains.annotations.Nullable;
 
 /**
- * Internal portable object interface.
+ * Extended binary object interface.
  */
-public abstract class BinaryObjectEx implements BinaryObject {
+public interface BinaryObjectEx extends BinaryObject {
     /**
-     * @return Length.
+     * @return Type ID.
      */
-    public abstract int length();
-
-    /**
-     * @return Object start.
-     */
-    public abstract int start();
-
-    /**
-     * @return {@code True} if object is array based.
-     */
-    protected abstract boolean hasArray();
-
-    /**
-     * @return Object array if object is array based, otherwise {@code null}.
-     */
-    public abstract byte[] array();
-
-    /**
-     * @return Object offheap address is object is offheap based, otherwise 0.
-     */
-    public abstract long offheapAddress();
-
-    /**
-     * Gets field value.
-     *
-     * @param fieldId Field ID.
-     * @return Field value.
-     * @throws org.apache.ignite.binary.BinaryObjectException In case of any other error.
-     */
-    @Nullable public abstract <F> F field(int fieldId) throws BinaryObjectException;
-
-    /**
-     * Get field by offset.
-     *
-     * @param fieldOffset Field offset.
-     * @return Field value.
-     */
-    @Nullable protected abstract <F> F fieldByOrder(int fieldOffset);
-
-    /**
-     * @param ctx Reader context.
-     * @param fieldName Field name.
-     * @return Field value.
-     */
-    @Nullable protected abstract <F> F field(BinaryReaderHandles ctx, String fieldName);
-
-    /**
-     * Get schema ID.
-     *
-     * @return Schema ID.
-     */
-    protected abstract int schemaId();
-
-    /**
-     * Create schema for object.
-     *
-     * @return Schema.
-     */
-    protected abstract PortableSchema createSchema();
-
-    /** {@inheritDoc} */
-    @Override public BinaryObject clone() throws CloneNotSupportedException {
-        return (BinaryObject)super.clone();
-    }
-
-    /** {@inheritDoc} */
-    public boolean equals(Object other) {
-        if (other == this)
-            return true;
-
-        if (other == null)
-            return false;
-
-        if (!(other instanceof BinaryObjectEx))
-            return false;
-
-        BinaryObjectEx otherPo = (BinaryObjectEx)other;
-
-        if (length() != otherPo.length() || typeId() != otherPo.typeId())
-            return false;
-
-        if (hasArray()) {
-            if (otherPo.hasArray()) {
-                int len = length();
-                int end = start() + len;
-
-                byte[] arr = array();
-                byte[] otherArr = otherPo.array();
-
-                for (int i = start(), j = otherPo.start(); i < end; i++, j++) {
-                    if (arr[i] != otherArr[j])
-                        return false;
-                }
-
-                return true;
-            }
-            else {
-                assert otherPo.offheapAddress() > 0;
-
-                return GridUnsafeMemory.compare(otherPo.offheapAddress() + otherPo.start(), array());
-            }
-        }
-        else {
-            assert offheapAddress() > 0;
-
-            if (otherPo.hasArray())
-                return GridUnsafeMemory.compare(offheapAddress() + start(), otherPo.array());
-            else {
-                assert otherPo.offheapAddress() > 0;
-
-                return GridUnsafeMemory.compare(offheapAddress() + start(),
-                    otherPo.offheapAddress() + otherPo.start(),
-                    length());
-            }
-        }
-    }
-
-    /**
-     * @param ctx Reader context.
-     * @param handles Handles for already traversed objects.
-     * @return String representation.
-     */
-    private String toString(BinaryReaderHandles ctx, IdentityHashMap<BinaryObject, Integer> handles) {
-        int idHash = System.identityHashCode(this);
-
-        BinaryType meta;
-
-        try {
-            meta = type();
-        }
-        catch (BinaryObjectException ignore) {
-            meta = null;
-        }
-
-        if (meta == null)
-            return BinaryObject.class.getSimpleName() +  " [hash=" + idHash + ", typeId=" + typeId() + ']';
-
-        handles.put(this, idHash);
-
-        SB buf = new SB(meta.typeName());
-
-        if (meta.fieldNames() != null) {
-            buf.a(" [hash=").a(idHash);
-
-            for (String name : meta.fieldNames()) {
-                Object val = field(ctx, name);
-
-                buf.a(", ").a(name).a('=');
-
-                if (val instanceof byte[])
-                    buf.a(Arrays.toString((byte[]) val));
-                else if (val instanceof short[])
-                    buf.a(Arrays.toString((short[])val));
-                else if (val instanceof int[])
-                    buf.a(Arrays.toString((int[])val));
-                else if (val instanceof long[])
-                    buf.a(Arrays.toString((long[])val));
-                else if (val instanceof float[])
-                    buf.a(Arrays.toString((float[])val));
-                else if (val instanceof double[])
-                    buf.a(Arrays.toString((double[])val));
-                else if (val instanceof char[])
-                    buf.a(Arrays.toString((char[])val));
-                else if (val instanceof boolean[])
-                    buf.a(Arrays.toString((boolean[]) val));
-                else if (val instanceof BigDecimal[])
-                    buf.a(Arrays.toString((BigDecimal[])val));
-                else {
-                    if (val instanceof BinaryObjectEx) {
-                        BinaryObjectEx po = (BinaryObjectEx)val;
-
-                        Integer idHash0 = handles.get(val);
-
-                        if (idHash0 != null) {  // Circular reference.
-                            BinaryType meta0 = po.type();
-
-                            assert meta0 != null;
-
-                            buf.a(meta0.typeName()).a(" [hash=").a(idHash0).a(", ...]");
-                        }
-                        else
-                            buf.a(po.toString(ctx, handles));
-                    }
-                    else
-                        buf.a(val);
-                }
-            }
-
-            buf.a(']');
-        }
-
-        return buf.toString();
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        try {
-            BinaryReaderHandles ctx = new BinaryReaderHandles();
-
-            ctx.put(start(), this);
-
-            return toString(ctx, new IdentityHashMap<BinaryObject, Integer>());
-        }
-        catch (BinaryObjectException e) {
-            throw new IgniteException("Failed to create string representation of portable object.", e);
-        }
-    }
-}
\ No newline at end of file
+    public int typeId();
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectExImpl.java
new file mode 100644
index 0000000..a32329a
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectExImpl.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.IdentityHashMap;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
+import org.apache.ignite.internal.util.typedef.internal.SB;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.binary.BinaryObject;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Internal portable object interface.
+ */
+public abstract class BinaryObjectExImpl implements BinaryObjectEx {
+    /**
+     * @return Length.
+     */
+    public abstract int length();
+
+    /**
+     * @return Object start.
+     */
+    public abstract int start();
+
+    /**
+     * @return {@code True} if object is array based.
+     */
+    protected abstract boolean hasArray();
+
+    /**
+     * @return Object array if object is array based, otherwise {@code null}.
+     */
+    public abstract byte[] array();
+
+    /**
+     * @return Object offheap address is object is offheap based, otherwise 0.
+     */
+    public abstract long offheapAddress();
+
+    /**
+     * Gets field value.
+     *
+     * @param fieldId Field ID.
+     * @return Field value.
+     * @throws org.apache.ignite.binary.BinaryObjectException In case of any other error.
+     */
+    @Nullable public abstract <F> F field(int fieldId) throws BinaryObjectException;
+
+    /** {@inheritDoc} */
+    @Override public int enumOrdinal() throws BinaryObjectException {
+        throw new BinaryObjectException("Object is not enum.");
+    }
+
+    /**
+     * Get field by offset.
+     *
+     * @param fieldOffset Field offset.
+     * @return Field value.
+     */
+    @Nullable protected abstract <F> F fieldByOrder(int fieldOffset);
+
+    /**
+     * @param ctx Reader context.
+     * @param fieldName Field name.
+     * @return Field value.
+     */
+    @Nullable protected abstract <F> F field(BinaryReaderHandles ctx, String fieldName);
+
+    /**
+     * Get schema ID.
+     *
+     * @return Schema ID.
+     */
+    protected abstract int schemaId();
+
+    /**
+     * Create schema for object.
+     *
+     * @return Schema.
+     */
+    protected abstract PortableSchema createSchema();
+
+    /** {@inheritDoc} */
+    @Override public BinaryObject clone() throws CloneNotSupportedException {
+        return (BinaryObject)super.clone();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (other == this)
+            return true;
+
+        if (other == null)
+            return false;
+
+        if (!(other instanceof BinaryObjectExImpl))
+            return false;
+
+        BinaryObjectExImpl otherPo = (BinaryObjectExImpl)other;
+
+        if (length() != otherPo.length() || typeId() != otherPo.typeId())
+            return false;
+
+        if (hasArray()) {
+            if (otherPo.hasArray()) {
+                int len = length();
+                int end = start() + len;
+
+                byte[] arr = array();
+                byte[] otherArr = otherPo.array();
+
+                for (int i = start(), j = otherPo.start(); i < end; i++, j++) {
+                    if (arr[i] != otherArr[j])
+                        return false;
+                }
+
+                return true;
+            }
+            else {
+                assert otherPo.offheapAddress() > 0;
+
+                return GridUnsafeMemory.compare(otherPo.offheapAddress() + otherPo.start(), array());
+            }
+        }
+        else {
+            assert offheapAddress() > 0;
+
+            if (otherPo.hasArray())
+                return GridUnsafeMemory.compare(offheapAddress() + start(), otherPo.array());
+            else {
+                assert otherPo.offheapAddress() > 0;
+
+                return GridUnsafeMemory.compare(offheapAddress() + start(),
+                    otherPo.offheapAddress() + otherPo.start(),
+                    length());
+            }
+        }
+    }
+
+    /**
+     * @param ctx Reader context.
+     * @param handles Handles for already traversed objects.
+     * @return String representation.
+     */
+    private String toString(BinaryReaderHandles ctx, IdentityHashMap<BinaryObject, Integer> handles) {
+        int idHash = System.identityHashCode(this);
+        int hash = hashCode();
+
+        BinaryType meta;
+
+        try {
+            meta = type();
+        }
+        catch (BinaryObjectException ignore) {
+            meta = null;
+        }
+
+        if (meta == null)
+            return BinaryObject.class.getSimpleName() +  " [idHash=" + idHash + ", hash=" + hash + ", typeId=" + typeId() + ']';
+
+        handles.put(this, idHash);
+
+        SB buf = new SB(meta.typeName());
+
+        if (meta.fieldNames() != null) {
+            buf.a(" [idHash=").a(idHash).a(", hash=").a(hash);
+
+            for (String name : meta.fieldNames()) {
+                Object val = field(ctx, name);
+
+                buf.a(", ").a(name).a('=');
+
+                if (val instanceof byte[])
+                    buf.a(Arrays.toString((byte[]) val));
+                else if (val instanceof short[])
+                    buf.a(Arrays.toString((short[])val));
+                else if (val instanceof int[])
+                    buf.a(Arrays.toString((int[])val));
+                else if (val instanceof long[])
+                    buf.a(Arrays.toString((long[])val));
+                else if (val instanceof float[])
+                    buf.a(Arrays.toString((float[])val));
+                else if (val instanceof double[])
+                    buf.a(Arrays.toString((double[])val));
+                else if (val instanceof char[])
+                    buf.a(Arrays.toString((char[])val));
+                else if (val instanceof boolean[])
+                    buf.a(Arrays.toString((boolean[]) val));
+                else if (val instanceof BigDecimal[])
+                    buf.a(Arrays.toString((BigDecimal[])val));
+                else {
+                    if (val instanceof BinaryObjectExImpl) {
+                        BinaryObjectExImpl po = (BinaryObjectExImpl)val;
+
+                        Integer idHash0 = handles.get(val);
+
+                        if (idHash0 != null) {  // Circular reference.
+                            BinaryType meta0 = po.type();
+
+                            assert meta0 != null;
+
+                            buf.a(meta0.typeName()).a(" [hash=").a(idHash0).a(", ...]");
+                        }
+                        else
+                            buf.a(po.toString(ctx, handles));
+                    }
+                    else
+                        buf.a(val);
+                }
+            }
+
+            buf.a(']');
+        }
+
+        return buf.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        try {
+            BinaryReaderHandles ctx = new BinaryReaderHandles();
+
+            ctx.put(start(), this);
+
+            return toString(ctx, new IdentityHashMap<BinaryObject, Integer>());
+        }
+        catch (BinaryObjectException e) {
+            throw new IgniteException("Failed to create string representation of portable object.", e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
index 7db4b4a..cf5a659 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectImpl.java
@@ -64,10 +64,7 @@
  * Portable object implementation.
  */
 @IgniteCodeGeneratingFail // Fields arr and start should not be generated by MessageCodeGenerator.
-public final class BinaryObjectImpl extends BinaryObjectEx implements Externalizable, KeyCacheObject {
-    /** */
-    public static final byte TYPE_BINARY = 100;
-
+public final class BinaryObjectImpl extends BinaryObjectExImpl implements Externalizable, KeyCacheObject {
     /** */
     private static final long serialVersionUID = 0L;
 
@@ -130,7 +127,7 @@
     @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean cpy) {
         Object obj0 = obj;
 
-        if (obj0 == null || cpy)
+        if (obj0 == null || (cpy && needCopy(ctx)))
             obj0 = deserializeValue(ctx);
 
         return (T)obj0;
@@ -564,6 +561,14 @@
     }
 
     /**
+     * @param ctx Context.
+     * @return {@code True} need to copy value returned to user.
+     */
+    private boolean needCopy(CacheObjectContext ctx) {
+        return ctx.copyOnGet() && obj != null && !ctx.processor().immutable(obj);
+    }
+
+    /**
      * Create new reader for this object.
      *
      * @param rCtx Reader context.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
index 8b8e0e8..6de0432 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryObjectOffheapImpl.java
@@ -61,7 +61,7 @@
 /**
  *  Portable object implementation over offheap memory
  */
-public class BinaryObjectOffheapImpl extends BinaryObjectEx implements Externalizable, CacheObject {
+public class BinaryObjectOffheapImpl extends BinaryObjectExImpl implements Externalizable, CacheObject {
     /** */
     private static final long serialVersionUID = 0L;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
index 4809c3c..b9f851c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryReaderExImpl.java
@@ -162,6 +162,20 @@
      */
     public BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, ClassLoader ldr,
         @Nullable BinaryReaderHandles hnds) {
+        this(ctx, in, ldr, hnds, false);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Context.
+     * @param in Input stream.
+     * @param ldr Class loader.
+     * @param hnds Context.
+     * @param skipHdrCheck Whether to skip header check.
+     */
+    public BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, ClassLoader ldr,
+        @Nullable BinaryReaderHandles hnds, boolean skipHdrCheck) {
         // Initialize base members.
         this.ctx = ctx;
         this.in = in;
@@ -170,10 +184,8 @@
 
         start = in.position();
 
-        byte hdr = in.readByte();
-
         // Perform full header parsing in case of portable object.
-        if (hdr == GridPortableMarshaller.OBJ) {
+        if (!skipHdrCheck && (in.readByte() == GridPortableMarshaller.OBJ)) {
             // Ensure protocol is fine.
             PortableUtils.checkProtocolVersion(in.readByte());
 
@@ -222,7 +234,7 @@
                 int off = in.position();
 
                 // Registers class by type ID, at least locally if the cache is not ready yet.
-                typeId = ctx.descriptorForClass(PortableUtils.doReadClass(in, ctx, ldr, typeId0)).typeId();
+                typeId = ctx.descriptorForClass(PortableUtils.doReadClass(in, ctx, ldr, typeId0), false).typeId();
 
                 int clsNameLen = in.position() - off;
 
@@ -265,7 +277,7 @@
      * @return Descriptor.
      */
     PortableClassDescriptor descriptor() {
-        return ctx.descriptorForTypeId(userType, typeId, ldr);
+        return ctx.descriptorForTypeId(userType, typeId, ldr, true);
     }
 
     /**
@@ -1415,7 +1427,7 @@
                 break;
 
             case OBJ:
-                PortableClassDescriptor desc = ctx.descriptorForTypeId(userType, typeId, ldr);
+                PortableClassDescriptor desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
 
                 streamPosition(dataStart);
 
@@ -1604,7 +1616,7 @@
                 break;
 
             case OPTM_MARSH:
-                obj = PortableUtils.doReadOptimized(in, ctx);
+                obj = PortableUtils.doReadOptimized(in, ctx, ldr);
 
                 break;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
index 5f2a91e..f471af2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryTypeImpl.java
@@ -48,6 +48,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public int typeId() {
+        return meta.typeId();
+    }
+
+    /** {@inheritDoc} */
     @Override public Collection<String> fieldNames() {
         return meta.fields();
     }
@@ -67,8 +72,13 @@
         return meta.affinityKeyFieldName();
     }
 
+    /** {@inheritDoc} */
+    @Override public boolean isEnum() {
+        return meta.isEnum();
+    }
+
     /**
-     * @return Portable context.
+     * @return Context.
      */
     public PortableContext context() {
         return ctx;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java
index a26b741..bd73ad0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriteMode.java
@@ -141,6 +141,9 @@
     /** */
     ENUM(GridPortableMarshaller.ENUM),
 
+    /** Portable enum. */
+    PORTABLE_ENUM(GridPortableMarshaller.ENUM),
+
     /** */
     ENUM_ARR(GridPortableMarshaller.ENUM_ARR),
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
index ec47f57..95807ea 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
@@ -182,7 +182,7 @@
 
         Class<?> cls = obj.getClass();
 
-        PortableClassDescriptor desc = ctx.descriptorForClass(cls);
+        PortableClassDescriptor desc = ctx.descriptorForClass(cls, false);
 
         if (desc == null)
             throw new BinaryObjectException("Object is not portable: [class=" + cls + ']');
@@ -697,7 +697,7 @@
             if (tryWriteAsHandle(val))
                 return;
 
-            PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType());
+            PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType(), false);
 
             out.unsafeEnsure(1 + 4);
             out.unsafeWriteByte(OBJ_ARR);
@@ -785,7 +785,7 @@
         if (val == null)
             out.writeByte(NULL);
         else {
-            PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass());
+            PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass(), false);
 
             out.unsafeEnsure(1 + 4);
 
@@ -803,6 +803,25 @@
     }
 
     /**
+     * @param val Value.
+     */
+    void doWritePortableEnum(BinaryEnumObjectImpl val) {
+        assert val != null;
+
+        int typeId = val.typeId();
+
+        out.unsafeEnsure(1 + 4);
+
+        out.unsafeWriteByte(ENUM);
+        out.unsafeWriteInt(typeId);
+
+        if (typeId == UNREGISTERED_TYPE_ID)
+            doWriteString(val.className());
+
+        out.writeInt(val.enumOrdinal());
+    }
+
+    /**
      * @param val Array.
      */
     void doWriteEnumArray(@Nullable Object[] val) {
@@ -811,7 +830,7 @@
         if (val == null)
             out.writeByte(NULL);
         else {
-            PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType());
+            PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType(), false);
 
             out.unsafeEnsure(1 + 4);
 
@@ -840,7 +859,7 @@
         if (val == null)
             out.writeByte(NULL);
         else {
-            PortableClassDescriptor desc = ctx.descriptorForClass(val);
+            PortableClassDescriptor desc = ctx.descriptorForClass(val, false);
 
             out.unsafeEnsure(1 + 4);
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
index af1ed68..5244da8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMarshaller.java
@@ -173,6 +173,9 @@
     public static final byte CONC_SKIP_LIST_SET = 6;
 
     /** */
+    public static final byte CONC_LINKED_QUEUE = 7;
+
+    /** */
     public static final byte HASH_MAP = 1;
 
     /** */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
index 78d4bc5..984f7c9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
@@ -161,8 +161,12 @@
 
         if (excluded)
             mode = BinaryWriteMode.EXCLUSION;
-        else
-            mode = serializer != null ? BinaryWriteMode.PORTABLE : PortableUtils.mode(cls);
+        else {
+            if (cls == BinaryEnumObjectImpl.class)
+                mode = BinaryWriteMode.PORTABLE_ENUM;
+            else
+                mode = serializer != null ? BinaryWriteMode.PORTABLE : PortableUtils.mode(cls);
+        }
 
         switch (mode) {
             case P_BYTE:
@@ -205,6 +209,7 @@
             case MAP_ENTRY:
             case PORTABLE_OBJ:
             case ENUM:
+            case PORTABLE_ENUM:
             case ENUM_ARR:
             case CLASS:
             case EXCLUSION:
@@ -244,7 +249,8 @@
                             String name = f.getName();
 
                             if (!names.add(name))
-                                throw new BinaryObjectException("Duplicate field name: " + name);
+                                throw new BinaryObjectException("Duplicate field name [fieldName=" + name +
+                                    ", cls=" + cls.getName() + ']');
 
                             int fieldId = idMapper.fieldId(typeId, name);
 
@@ -286,6 +292,13 @@
     }
 
     /**
+     * @return {@code True} if enum.
+     */
+    boolean isEnum() {
+        return mode == BinaryWriteMode.ENUM;
+    }
+
+    /**
      * @return Described class.
      */
     Class<?> describedClass() {
@@ -328,7 +341,7 @@
     }
 
     /**
-     * @return {@code true} if {@link OptimizedMarshaller} must be used instead of {@link org.apache.ignite.marshaller.portable.BinaryMarshaller}
+     * @return {@code true} if {@link OptimizedMarshaller} must be used instead of {@link BinaryMarshaller}
      * for object serialization and deserialization.
      */
     public boolean useOptimizedMarshaller() {
@@ -534,6 +547,11 @@
 
                 break;
 
+            case PORTABLE_ENUM:
+                writer.doWritePortableEnum((BinaryEnumObjectImpl)obj);
+
+                break;
+
             case ENUM_ARR:
                 writer.doWriteEnumArray((Object[])obj);
 
@@ -576,7 +594,7 @@
                                 PortableSchema newSchema = collector.schema();
 
                                 BinaryMetadata meta = new BinaryMetadata(typeId, typeName, collector.meta(),
-                                    affKeyFieldName, Collections.singleton(newSchema));
+                                    affKeyFieldName, Collections.singleton(newSchema), false);
 
                                 ctx.updateMetadata(typeId, meta);
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
index 01bc9d8..1482df9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
@@ -24,6 +24,7 @@
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.io.ObjectStreamException;
+import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.net.URISyntaxException;
 import java.net.URL;
@@ -46,12 +47,14 @@
 import java.util.TreeSet;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.CacheKeyConfiguration;
+import org.apache.ignite.cache.affinity.AffinityKeyMapped;
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.binary.BinaryTypeConfiguration;
@@ -71,7 +74,6 @@
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.marshaller.MarshallerContext;
 import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
 
@@ -115,6 +117,9 @@
     /** */
     private BinaryMetadataHandler metaHnd;
 
+    /** Actual marshaller. */
+    private BinaryMarshaller marsh;
+
     /** */
     private MarshallerContext marshCtx;
 
@@ -159,6 +164,7 @@
         colTypes.put(LinkedHashSet.class, GridPortableMarshaller.LINKED_HASH_SET);
         colTypes.put(TreeSet.class, GridPortableMarshaller.TREE_SET);
         colTypes.put(ConcurrentSkipListSet.class, GridPortableMarshaller.CONC_SKIP_LIST_SET);
+        colTypes.put(ConcurrentLinkedQueue.class, GridPortableMarshaller.CONC_LINKED_QUEUE);
 
         mapTypes.put(HashMap.class, GridPortableMarshaller.HASH_MAP);
         mapTypes.put(LinkedHashMap.class, GridPortableMarshaller.LINKED_HASH_MAP);
@@ -219,6 +225,13 @@
     }
 
     /**
+     * @return Marshaller.
+     */
+    public BinaryMarshaller marshaller() {
+        return marsh;
+    }
+
+    /**
      * @param marsh Portable marshaller.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
@@ -226,6 +239,8 @@
         if (marsh == null)
             return;
 
+        this.marsh = marsh;
+
         marshCtx = marsh.getContext();
 
         BinaryConfiguration binaryCfg = cfg.getBinaryConfiguration();
@@ -290,16 +305,27 @@
 
                     for (String clsName0 : classesInPackage(pkgName))
                         descs.add(clsName0, idMapper, serializer, affFields.get(clsName0),
-                            true);
+                            typeCfg.isEnum(), true);
                 }
                 else
                     descs.add(clsName, idMapper, serializer, affFields.get(clsName),
-                        false);
+                        typeCfg.isEnum(), false);
             }
         }
 
         for (TypeDescriptor desc : descs.descriptors()) {
-            registerUserType(desc.clsName, desc.idMapper, desc.serializer, desc.affKeyFieldName);
+            registerUserType(desc.clsName, desc.idMapper, desc.serializer, desc.affKeyFieldName, desc.isEnum);
+        }
+
+        BinaryInternalIdMapper dfltMapper = BinaryInternalIdMapper.create(globalIdMapper);
+
+        // Put affinity field names for unconfigured types.
+        for (Map.Entry<String, String> entry : affFields.entrySet()) {
+            String typeName = entry.getKey();
+
+            int typeId = dfltMapper.typeId(typeName);
+
+            affKeyFieldNames.putIfAbsent(typeId, entry.getValue());
         }
     }
 
@@ -376,14 +402,14 @@
      * @return Class descriptor.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
-    public PortableClassDescriptor descriptorForClass(Class<?> cls)
+    public PortableClassDescriptor descriptorForClass(Class<?> cls, boolean deserialize)
         throws BinaryObjectException {
         assert cls != null;
 
         PortableClassDescriptor desc = descByCls.get(cls);
 
         if (desc == null || !desc.registered())
-            desc = registerClassDescriptor(cls);
+            desc = registerClassDescriptor(cls, deserialize);
 
         return desc;
     }
@@ -394,7 +420,12 @@
      * @param ldr Class loader.
      * @return Class descriptor.
      */
-    public PortableClassDescriptor descriptorForTypeId(boolean userType, int typeId, ClassLoader ldr) {
+    public PortableClassDescriptor descriptorForTypeId(
+        boolean userType,
+        int typeId,
+        ClassLoader ldr,
+        boolean deserialize
+    ) {
         assert typeId != GridPortableMarshaller.UNREGISTERED_TYPE_ID;
 
         //TODO: As a workaround for IGNITE-1358 we always check the predefined map before without checking 'userType'
@@ -424,21 +455,21 @@
         }
         catch (ClassNotFoundException e) {
             // Class might have been loaded by default class loader.
-            if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr)) != null)
+            if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr, deserialize)) != null)
                 return desc;
 
             throw new BinaryInvalidTypeException(e);
         }
         catch (IgniteCheckedException e) {
             // Class might have been loaded by default class loader.
-            if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr)) != null)
+            if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr, deserialize)) != null)
                 return desc;
 
             throw new BinaryObjectException("Failed resolve class for ID: " + typeId, e);
         }
 
         if (desc == null) {
-            desc = registerClassDescriptor(cls);
+            desc = registerClassDescriptor(cls, deserialize);
 
             assert desc.typeId() == typeId;
         }
@@ -452,7 +483,7 @@
      * @param cls Class.
      * @return Class descriptor.
      */
-    private PortableClassDescriptor registerClassDescriptor(Class<?> cls) {
+    private PortableClassDescriptor registerClassDescriptor(Class<?> cls, boolean deserialize) {
         PortableClassDescriptor desc;
 
         String clsName = cls.getName();
@@ -477,7 +508,7 @@
                 desc = old;
         }
         else
-            desc = registerUserClassDescriptor(cls);
+            desc = registerUserClassDescriptor(cls, deserialize);
 
         return desc;
     }
@@ -488,7 +519,7 @@
      * @param cls Class.
      * @return Class descriptor.
      */
-    private PortableClassDescriptor registerUserClassDescriptor(Class<?> cls) {
+    private PortableClassDescriptor registerUserClassDescriptor(Class<?> cls, boolean deserialize) {
         boolean registered;
 
         String typeName = typeName(cls.getName());
@@ -504,12 +535,14 @@
             throw new BinaryObjectException("Failed to register class.", e);
         }
 
+        String affFieldName = affinityFieldName(cls);
+
         PortableClassDescriptor desc = new PortableClassDescriptor(this,
             cls,
             true,
             typeId,
             typeName,
-            null,
+            affFieldName,
             idMapper,
             null,
             true,
@@ -517,9 +550,12 @@
             false /* predefined */
         );
 
-        Collection<PortableSchema> schemas = desc.schema() != null ? Collections.singleton(desc.schema()) : null;
+        if (!deserialize) {
+            Collection<PortableSchema> schemas = desc.schema() != null ? Collections.singleton(desc.schema()) : null;
 
-        metaHnd.addMeta(typeId, new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), null, schemas).wrap(this));
+            metaHnd.addMeta(typeId,
+                new BinaryMetadata(typeId, typeName, desc.fieldsMeta(), affFieldName, schemas, desc.isEnum()).wrap(this));
+        }
 
         // perform put() instead of putIfAbsent() because "registered" flag might have been changed or class loader
         // might have reloaded described class.
@@ -607,6 +643,21 @@
         return idMapper != null ? idMapper : BinaryInternalIdMapper.defaultInstance();
     }
 
+    /**
+     * @param cls Class to get affinity field for.
+     * @return Affinity field name or {@code null} if field name was not found.
+     */
+    private String affinityFieldName(Class cls) {
+        for (; cls != Object.class && cls != null; cls = cls.getSuperclass()) {
+            for (Field f : cls.getDeclaredFields()) {
+                if (f.getAnnotation(AffinityKeyMapped.class) != null)
+                    return f.getName();
+            }
+        }
+
+        return null;
+    }
+
     /** {@inheritDoc} */
     @Override public void writeExternal(ObjectOutput out) throws IOException {
         U.writeString(out, igniteCfg.getGridName());
@@ -670,13 +721,15 @@
      * @param idMapper ID mapper.
      * @param serializer Serializer.
      * @param affKeyFieldName Affinity key field name.
+     * @param isEnum If enum.
      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
      */
     @SuppressWarnings("ErrorNotRethrown")
     public void registerUserType(String clsName,
         BinaryIdMapper idMapper,
         @Nullable BinarySerializer serializer,
-        @Nullable String affKeyFieldName)
+        @Nullable String affKeyFieldName,
+        boolean isEnum)
         throws BinaryObjectException {
         assert idMapper != null;
 
@@ -734,7 +787,7 @@
             descByCls.put(cls, desc);
         }
 
-        metaHnd.addMeta(id, new BinaryMetadata(id, typeName, fieldsMeta, affKeyFieldName, schemas).wrap(this));
+        metaHnd.addMeta(id, new BinaryMetadata(id, typeName, fieldsMeta, affKeyFieldName, schemas, isEnum).wrap(this));
     }
 
     /**
@@ -864,8 +917,12 @@
                 // This is an anonymous class. Don't cut off enclosing class name for it.
                 idx = -1;
             }
-            catch (NumberFormatException e) {
-                return typeName;
+            catch (NumberFormatException ignore) {
+                // This is a lambda class.
+                if (clsName.indexOf("$$Lambda$") > 0)
+                    idx = -1;
+                else
+                    return typeName;
             }
         }
 
@@ -905,6 +962,7 @@
          * @param idMapper ID mapper.
          * @param serializer Serializer.
          * @param affKeyFieldName Affinity key field name.
+         * @param isEnum Enum flag.
          * @param canOverride Whether this descriptor can be override.
          * @throws org.apache.ignite.binary.BinaryObjectException If failed.
          */
@@ -912,12 +970,14 @@
             BinaryIdMapper idMapper,
             BinarySerializer serializer,
             String affKeyFieldName,
+            boolean isEnum,
             boolean canOverride)
             throws BinaryObjectException {
             TypeDescriptor desc = new TypeDescriptor(clsName,
                 idMapper,
                 serializer,
                 affKeyFieldName,
+                isEnum,
                 canOverride);
 
             TypeDescriptor oldDesc = descs.get(clsName);
@@ -954,6 +1014,9 @@
         /** Affinity key field name. */
         private String affKeyFieldName;
 
+        /** Enum flag. */
+        private boolean isEnum;
+
         /** Whether this descriptor can be override. */
         private boolean canOverride;
 
@@ -964,14 +1027,16 @@
          * @param idMapper ID mapper.
          * @param serializer Serializer.
          * @param affKeyFieldName Affinity key field name.
+         * @param isEnum Enum type.
          * @param canOverride Whether this descriptor can be override.
          */
         private TypeDescriptor(String clsName, BinaryIdMapper idMapper, BinarySerializer serializer,
-            String affKeyFieldName, boolean canOverride) {
+            String affKeyFieldName, boolean isEnum, boolean canOverride) {
             this.clsName = clsName;
             this.idMapper = idMapper;
             this.serializer = serializer;
             this.affKeyFieldName = affKeyFieldName;
+            this.isEnum = isEnum;
             this.canOverride = canOverride;
         }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
index 5c798b8..5d794ca 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.portable;
 
+import java.util.concurrent.ConcurrentLinkedQueue;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryInvalidTypeException;
 import org.apache.ignite.binary.BinaryObject;
@@ -68,6 +69,7 @@
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.CLASS;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.COL;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.CONC_HASH_MAP;
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.CONC_LINKED_QUEUE;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.CONC_SKIP_LIST_SET;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE;
 import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE_ARR;
@@ -875,6 +877,16 @@
                 );
             }
 
+            // Check enum flag.
+            if (oldMeta.isEnum() != newMeta.isEnum()) {
+                if (oldMeta.isEnum())
+                    throw new BinaryObjectException("Binary type already registered as enum: " +
+                        newMeta.typeName());
+                else
+                    throw new BinaryObjectException("Binary type already registered as non-enum: " +
+                        newMeta.typeName());
+            }
+
             // Check and merge fields.
             boolean changed = false;
 
@@ -906,7 +918,7 @@
 
             // Return either old meta if no changes detected, or new merged meta.
             return changed ? new BinaryMetadata(oldMeta.typeId(), oldMeta.typeName(), mergedFields,
-                oldMeta.affinityKeyFieldName(), mergedSchemas) : oldMeta;
+                oldMeta.affinityKeyFieldName(), mergedSchemas, oldMeta.isEnum()) : oldMeta;
         }
     }
 
@@ -1312,6 +1324,37 @@
     }
 
     /**
+     * Read plain type.
+     *
+     * @param in Input stream.
+     * @return Plain type.
+     */
+    private static EnumType doReadEnumType(PortableInputStream in) {
+        int typeId = in.readInt();
+
+        if (typeId != UNREGISTERED_TYPE_ID)
+            return new EnumType(typeId, null);
+        else {
+            String clsName = doReadClassName(in);
+
+            return new EnumType(UNREGISTERED_TYPE_ID, clsName);
+        }
+    }
+
+    /**
+     * @param in Input stream.
+     * @return Class name.
+     */
+    private static String doReadClassName(PortableInputStream in) {
+        byte flag = in.readByte();
+
+        if (flag != STRING)
+            throw new BinaryObjectException("Failed to read class name [position=" + (in.position() - 1) + ']');
+
+        return doReadString(in);
+    }
+
+    /**
      * @param typeId Type id.
      * @return Value.
      */
@@ -1323,14 +1366,9 @@
             return Object.class;
 
         if (typeId != UNREGISTERED_TYPE_ID)
-            cls = ctx.descriptorForTypeId(true, typeId, ldr).describedClass();
+            cls = ctx.descriptorForTypeId(true, typeId, ldr, false).describedClass();
         else {
-            byte flag = in.readByte();
-
-            if (flag != STRING)
-                throw new BinaryObjectException("No class definition for typeId: " + typeId);
-
-            String clsName = doReadString(in);
+            String clsName = doReadClassName(in);
 
             try {
                 cls = U.forName(clsName, ldr);
@@ -1340,13 +1378,83 @@
             }
 
             // forces registering of class by type id, at least locally
-            ctx.descriptorForClass(cls);
+            ctx.descriptorForClass(cls, true);
         }
 
         return cls;
     }
 
     /**
+     * Resolve the class.
+     *
+     * @param ctx Portable context.
+     * @param typeId Type ID.
+     * @param clsName Class name.
+     * @param ldr Class loaded.
+     * @return Resovled class.
+     */
+    public static Class resolveClass(PortableContext ctx, int typeId, @Nullable String clsName,
+        @Nullable ClassLoader ldr, boolean deserialize) {
+        Class cls;
+
+        if (typeId == OBJECT_TYPE_ID)
+            return Object.class;
+
+        if (typeId != UNREGISTERED_TYPE_ID)
+            cls = ctx.descriptorForTypeId(true, typeId, ldr, deserialize).describedClass();
+        else {
+            try {
+                cls = U.forName(clsName, ldr);
+            }
+            catch (ClassNotFoundException e) {
+                throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
+            }
+
+            // forces registering of class by type id, at least locally
+            ctx.descriptorForClass(cls, true);
+        }
+
+        return cls;
+    }
+
+    /**
+     * Read portable enum.
+     *
+     * @param in Input stream.
+     * @param ctx Portable context.
+     * @param type Plain type.
+     * @return Enum.
+     */
+    private static BinaryEnumObjectImpl doReadPortableEnum(PortableInputStream in, PortableContext ctx,
+        EnumType type) {
+        return new BinaryEnumObjectImpl(ctx, type.typeId, type.clsName, in.readInt());
+    }
+
+    /**
+     * Read portable enum array.
+     *
+     * @param in Input stream.
+     * @param ctx Portable context.
+     * @return Enum array.
+     */
+    private static Object[] doReadPortableEnumArray(PortableInputStream in, PortableContext ctx) {
+        int len = in.readInt();
+
+        Object[] arr = (Object[]) Array.newInstance(BinaryObject.class, len);
+
+        for (int i = 0; i < len; i++) {
+            byte flag = in.readByte();
+
+            if (flag == NULL)
+                arr[i] = null;
+            else
+                arr[i] = doReadPortableEnum(in, ctx, doReadEnumType(in));
+        }
+
+        return arr;
+    }
+
+    /**
      * Having target class in place we simply read ordinal and create final representation.
      *
      * @param cls Enum class.
@@ -1390,13 +1498,13 @@
      *
      * @return Result.
      */
-    public static Object doReadOptimized(PortableInputStream in, PortableContext ctx) {
+    public static Object doReadOptimized(PortableInputStream in, PortableContext ctx, @Nullable ClassLoader clsLdr) {
         int len = in.readInt();
 
         ByteArrayInputStream input = new ByteArrayInputStream(in.array(), in.position(), len);
 
         try {
-            return ctx.optimizedMarsh().unmarshal(input, null);
+            return ctx.optimizedMarsh().unmarshal(input, clsLdr);
         }
         catch (IgniteCheckedException e) {
             throw new BinaryObjectException("Failed to unmarshal object with optimized marshaller", e);
@@ -1470,7 +1578,7 @@
 
                 int len = length(in, start);
 
-                BinaryObjectEx po;
+                BinaryObjectExImpl po;
 
                 if (detach) {
                     // In detach mode we simply copy object's content.
@@ -1587,16 +1695,18 @@
                 return doReadPortableObject(in, ctx);
 
             case ENUM:
-                return doReadEnum(in, doReadClass(in, ctx, ldr));
+                return doReadPortableEnum(in, ctx, doReadEnumType(in));
 
             case ENUM_ARR:
-                return doReadEnumArray(in, ctx, ldr, doReadClass(in, ctx, ldr));
+                doReadEnumType(in); // Simply skip this part as we do not need it.
+
+                return doReadPortableEnumArray(in, ctx);
 
             case CLASS:
                 return doReadClass(in, ctx, ldr);
 
             case OPTM_MARSH:
-                return doReadOptimized(in, ctx);
+                return doReadOptimized(in, ctx, ldr);
 
             default:
                 throw new BinaryObjectException("Invalid flag value: " + flag);
@@ -1692,6 +1802,11 @@
 
                     break;
 
+                case CONC_LINKED_QUEUE:
+                    col = new ConcurrentLinkedQueue<>();
+
+                    break;
+
                 case USER_SET:
                     col = U.newHashSet(size);
 
@@ -1836,4 +1951,29 @@
     public static int positionForHandle(PortableInputStream in) {
         return in.position() - 1;
     }
+
+    /**
+     * Enum type.
+     */
+    private static class EnumType {
+        /** Type ID. */
+        private final int typeId;
+
+        /** Class name. */
+        private final String clsName;
+
+        /**
+         * Constructor.
+         *
+         * @param typeId Type ID.
+         * @param clsName Class name.
+         */
+        public EnumType(int typeId, @Nullable String clsName) {
+            assert typeId != UNREGISTERED_TYPE_ID && clsName == null ||
+                typeId == UNREGISTERED_TYPE_ID && clsName != null;
+
+            this.typeId = typeId;
+            this.clsName = clsName;
+        }
+    }
 }
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
index b2fb7d8..c4ce9e6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
@@ -31,7 +31,6 @@
 import org.apache.ignite.internal.portable.PortableSchema;
 import org.apache.ignite.internal.portable.PortableSchemaRegistry;
 import org.apache.ignite.internal.portable.PortableUtils;
-import org.apache.ignite.internal.util.GridArgumentCheck;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
@@ -162,7 +161,7 @@
                 throw new BinaryInvalidTypeException("Failed to load the class: " + clsNameToWrite, e);
             }
 
-            this.typeId = ctx.descriptorForClass(cls).typeId();
+            this.typeId = ctx.descriptorForClass(cls, false).typeId();
 
             registeredType = false;
 
@@ -312,10 +311,16 @@
 
                     String oldFldTypeName = meta == null ? null : meta.fieldTypeName(name);
 
+                    boolean nullObjField = false;
+
                     int newFldTypeId;
 
-                    if (val instanceof PortableValueWithType)
-                        newFldTypeId = ((PortableValueWithType) val).typeId();
+                    if (val instanceof PortableValueWithType) {
+                        newFldTypeId = ((PortableValueWithType)val).typeId();
+
+                        if (newFldTypeId == GridPortableMarshaller.OBJ && ((PortableValueWithType)val).value() == null)
+                            nullObjField = true;
+                    }
                     else
                         newFldTypeId = PortableUtils.typeByClass(val.getClass());
 
@@ -328,7 +333,7 @@
 
                         fieldsMeta.put(name, PortableUtils.fieldTypeId(newFldTypeName));
                     }
-                    else {
+                    else if (!nullObjField) {
                         String objTypeName = PortableUtils.fieldTypeName(GridPortableMarshaller.OBJ);
 
                         if (!objTypeName.equals(oldFldTypeName) && !oldFldTypeName.equals(newFldTypeName)) {
@@ -378,7 +383,7 @@
                 PortableSchema curSchema = writer.currentSchema();
 
                 ctx.updateMetadata(typeId, new BinaryMetadata(typeId, typeName, fieldsMeta,
-                    ctx.affinityKeyFieldName(typeId), Collections.singleton(curSchema)));
+                    ctx.affinityKeyFieldName(typeId), Collections.singleton(curSchema), false));
 
                 schemaReg.addSchema(curSchema.schemaId(), curSchema);
             }
@@ -492,15 +497,15 @@
     }
 
     /** {@inheritDoc} */
-    @Override public BinaryObjectBuilder setField(String name, Object val) {
-        GridArgumentCheck.notNull(val, name);
+    @Override public BinaryObjectBuilder setField(String name, Object val0) {
+        Object val = val0 == null ? new PortableValueWithType(PortableUtils.typeByClass(Object.class), null) : val0;
 
         if (assignedVals == null)
             assignedVals = new LinkedHashMap<>();
 
         Object oldVal = assignedVals.put(name, val);
 
-        if (oldVal instanceof PortableValueWithType) {
+        if (oldVal instanceof PortableValueWithType && val0 != null) {
             ((PortableValueWithType)oldVal).value(val);
 
             assignedVals.put(name, oldVal);
@@ -514,8 +519,6 @@
         if (assignedVals == null)
             assignedVals = new LinkedHashMap<>();
 
-        //int fldId = ctx.fieldId(typeId, fldName);
-
         assignedVals.put(name, new PortableValueWithType(PortableUtils.typeByClass(type), val));
 
         return this;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderEnum.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderEnum.java
index 9eb77b4..6f79e73 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderEnum.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderEnum.java
@@ -64,7 +64,7 @@
                 throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
             }
 
-            this.typeId = reader.portableContext().descriptorForClass(cls).typeId();
+            this.typeId = reader.portableContext().descriptorForClass(cls, false).typeId();
         }
         else {
             this.typeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderSerializer.java
index 0e8eaa4..52f84c6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderSerializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableBuilderSerializer.java
@@ -18,8 +18,10 @@
 package org.apache.ignite.internal.portable.builder;
 
 import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.internal.portable.BinaryMetadata;
 import org.apache.ignite.internal.portable.GridPortableMarshaller;
-import org.apache.ignite.internal.portable.BinaryObjectEx;
+import org.apache.ignite.internal.portable.BinaryObjectExImpl;
+import org.apache.ignite.internal.portable.PortableContext;
 import org.apache.ignite.internal.portable.PortableUtils;
 import org.apache.ignite.internal.portable.BinaryWriterExImpl;
 import org.apache.ignite.internal.util.*;
@@ -61,7 +63,7 @@
             return;
         }
 
-        if (val instanceof BinaryObjectEx) {
+        if (val instanceof BinaryObjectExImpl) {
             if (portableObjToWrapper == null)
                 portableObjToWrapper = new IdentityHashMap<>();
 
@@ -97,8 +99,14 @@
         }
 
         if (val.getClass().isEnum()) {
+            String typeName = PortableContext.typeName(val.getClass().getName());
+            int typeId = writer.context().typeId(typeName);
+
+            BinaryMetadata meta = new BinaryMetadata(typeId, typeName, null, null, null, true);
+            writer.context().updateMetadata(typeId, meta);
+
             writer.writeByte(GridPortableMarshaller.ENUM);
-            writer.writeInt(writer.context().typeId(val.getClass().getName()));
+            writer.writeInt(typeId);
             writer.writeInt(((Enum)val).ordinal());
 
             return;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableEnumArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableEnumArrayLazyValue.java
index 1e2ebc9..91c1c87 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableEnumArrayLazyValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableEnumArrayLazyValue.java
@@ -57,7 +57,7 @@
                 throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
             }
 
-            compTypeId = reader.portableContext().descriptorForClass(cls).typeId();
+            compTypeId = reader.portableContext().descriptorForClass(cls, true).typeId();
         }
         else {
             compTypeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableObjectArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableObjectArrayLazyValue.java
index 6634eea..8c8022b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableObjectArrayLazyValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/PortableObjectArrayLazyValue.java
@@ -56,7 +56,7 @@
                 throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
             }
 
-            compTypeId = reader.portableContext().descriptorForClass(cls).typeId();
+            compTypeId = reader.portableContext().descriptorForClass(cls, true).typeId();
         }
         else {
             compTypeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
new file mode 100644
index 0000000..efd38f7
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheDefaultBinaryAffinityKeyMapper.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.binary.BinaryObject;
+
+/**
+ *
+ */
+public class CacheDefaultBinaryAffinityKeyMapper extends GridCacheDefaultAffinityKeyMapper {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** {@inheritDoc} */
+    @Override public Object affinityKey(Object key) {
+        IgniteKernal kernal = (IgniteKernal)ignite;
+
+        CacheObjectBinaryProcessorImpl proc = (CacheObjectBinaryProcessorImpl)kernal.context().cacheObjects();
+
+        try {
+            key = proc.toPortable(key);
+        }
+        catch (IgniteException e) {
+            U.error(log, "Failed to marshal key to portable: " + key, e);
+        }
+
+        if (key instanceof BinaryObject)
+            return proc.affinityKey((BinaryObject)key);
+        else
+            return super.affinityKey(key);
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeResult.java
index 8d6d905..48dabb9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeResult.java
@@ -64,6 +64,20 @@
     }
 
     /**
+     * @return Result.
+     */
+    public T result() {
+        return res;
+    }
+
+    /**
+     * Entry processor error;
+     */
+    public Exception error() {
+        return err;
+    }
+
+    /**
      * Static constructor.
      *
      * @param err Exception thrown by {@link EntryProcessor#process(MutableEntry, Object...)}.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLazyEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLazyEntry.java
index 47ad30c..2b9efa3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLazyEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLazyEntry.java
@@ -103,7 +103,7 @@
     /** {@inheritDoc} */
     @Override public V getValue() {
         if (val == null)
-            val = (V)cctx.unwrapPortableIfNeeded(valObj, keepPortable);
+            val = (V)cctx.unwrapPortableIfNeeded(valObj, keepPortable, false);
 
         return val;
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockImpl.java
index 2e8dc9b..ae7b42e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockImpl.java
@@ -69,6 +69,8 @@
         CacheOperationContext prev = gate.enter(opCtx);
 
         try {
+            checkTx();
+
             delegate.lockAll(keys, 0);
 
             incrementLockCounter();
@@ -102,6 +104,8 @@
         CacheOperationContext prev = gate.enter(opCtx);
 
         try {
+            checkTx();
+
             boolean res = delegate.lockAll(keys, -1);
 
             if (res)
@@ -128,6 +132,8 @@
         CacheOperationContext prev = gate.enter(opCtx);
 
         try {
+            checkTx();
+
             IgniteInternalFuture<Boolean> fut = delegate.lockAllAsync(keys, unit.toMillis(time));
 
             try {
@@ -198,8 +204,18 @@
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * Verifies there is no ongoing user transaction.
+     *
+     * @throws CacheException
+     */
+    private void checkTx() throws CacheException {
+        if (delegate.context().tm().inUserTx())
+            throw new CacheException("Explicit lock can't be acquired within a transaction.");
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(CacheLockImpl.class, this);
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
index 81129bd..2385335 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
@@ -31,6 +31,9 @@
     /** */
     public static final byte TYPE_BYTE_ARR = 2;
 
+    /** */
+    public static final byte TYPE_BINARY = 100;
+
     /**
      * @param ctx Context.
      * @param cpy If {@code true} need to copy value.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java
index b3d2d4e4..fe650f3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectContext.java
@@ -176,6 +176,23 @@
     }
 
     /**
+     * Unwrap array of portables if needed.
+     *
+     * @param arr Array.
+     * @param keepPortable Keep portable flag.
+     * @param cpy Copy.
+     * @return Result.
+     */
+    public Object[] unwrapPortablesInArrayIfNeeded(Object[] arr, boolean keepPortable, boolean cpy) {
+        Object[] res = new Object[arr.length];
+
+        for (int i = 0; i < arr.length; i++)
+            res[i] = unwrapPortable(arr[i], keepPortable, cpy);
+
+        return res;
+    }
+
+    /**
      * Unwraps map.
      *
      * @param map Map to unwrap.
@@ -203,6 +220,8 @@
     private Collection<Object> unwrapPortables(ArrayList<Object> col, boolean keepPortable, boolean cpy) {
         int size = col.size();
 
+        col = new ArrayList<>(col);
+
         for (int i = 0; i < size; i++) {
             Object o = col.get(i);
 
@@ -252,11 +271,13 @@
             return unwrapPortablesIfNeeded((Collection<Object>)o, keepPortable, cpy);
         else if (o instanceof Map)
             return unwrapPortablesIfNeeded((Map<Object, Object>)o, keepPortable, cpy);
+        else if (o instanceof Object[])
+            return unwrapPortablesInArrayIfNeeded((Object[])o, keepPortable, cpy);
         else if (o instanceof CacheObject) {
             CacheObject co = (CacheObject)o;
 
             if (!keepPortable || co.isPlatformType())
-                return unwrapPortable(co.value(this, true), keepPortable, cpy);
+                return unwrapPortable(co.value(this, cpy), keepPortable, cpy);
         }
 
         return o;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
index 26a3acd..b5b8690 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
@@ -296,14 +296,14 @@
      */
     @SuppressWarnings("OverriddenMethodCallDuringObjectConstruction")
     protected GridCacheAdapter(GridCacheContext<K, V> ctx, int startSize) {
-        this(ctx, new GridCacheConcurrentMap(ctx, startSize, 0.75F, null));
+        this(ctx, new GridCacheConcurrentMap(ctx, startSize, null));
     }
 
     /**
      * @param ctx Cache context.
      * @param map Concurrent map.
      */
-    @SuppressWarnings("OverriddenMethodCallDuringObjectConstruction")
+    @SuppressWarnings({"OverriddenMethodCallDuringObjectConstruction", "deprecation"})
     protected GridCacheAdapter(final GridCacheContext<K, V> ctx, GridCacheConcurrentMap map) {
         assert ctx != null;
 
@@ -799,7 +799,7 @@
             else
                 cacheVal = localCachePeek0(cacheKey, modes.heap, modes.offheap, modes.swap, plc);
 
-            Object val = ctx.unwrapPortableIfNeeded(cacheVal, ctx.keepPortable());
+            Object val = ctx.unwrapPortableIfNeeded(cacheVal, ctx.keepPortable(), false);
 
             return (V)val;
         }
@@ -821,6 +821,7 @@
      * @throws GridCacheEntryRemovedException If entry removed.
      * @throws IgniteCheckedException If failed.
      */
+    @SuppressWarnings("ConstantConditions")
     @Nullable private CacheObject localCachePeek0(KeyCacheObject key,
         boolean heap,
         boolean offheap,
@@ -3601,6 +3602,14 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong(CachePeekMode[] peekModes) throws IgniteCheckedException {
+        if (isLocal())
+            return localSizeLong(peekModes);
+
+        return sizeLongAsync(peekModes).get();
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteInternalFuture<Integer> sizeAsync(final CachePeekMode[] peekModes) {
         assert peekModes != null;
 
@@ -3622,11 +3631,36 @@
     }
 
     /** {@inheritDoc} */
-    @SuppressWarnings("ForLoopReplaceableByForEach")
-    @Override public int localSize(CachePeekMode[] peekModes) throws IgniteCheckedException {
+    @Override public IgniteInternalFuture<Long> sizeLongAsync(final CachePeekMode[] peekModes) {
+        assert peekModes != null;
+
         PeekModes modes = parsePeekModes(peekModes, true);
 
-        int size = 0;
+        IgniteClusterEx cluster = ctx.grid().cluster();
+
+        ClusterGroup grp = modes.near ? cluster.forCacheNodes(name(), true, true, false) : cluster.forDataNodes(name());
+
+        Collection<ClusterNode> nodes = grp.nodes();
+
+        if (nodes.isEmpty())
+            return new GridFinishedFuture<>(0L);
+
+        ctx.kernalContext().task().setThreadContext(TC_SUBGRID, nodes);
+
+        return ctx.kernalContext().task().execute(
+            new SizeLongTask(ctx.name(), ctx.affinity().affinityTopologyVersion(), peekModes), null);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int localSize(CachePeekMode[] peekModes) throws IgniteCheckedException {
+        return (int)localSizeLong(peekModes);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long localSizeLong(CachePeekMode[] peekModes) throws IgniteCheckedException {
+        PeekModes modes = parsePeekModes(peekModes, true);
+
+        long size = 0;
 
         if (ctx.isLocal()) {
             modes.primary = true;
@@ -3676,6 +3710,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong() {
+        return map.publicSize();
+    }
+
+    /** {@inheritDoc} */
     @Override public int nearSize() {
         return 0;
     }
@@ -3686,6 +3725,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long primarySizeLong() {
+        return map.publicSize();
+    }
+
+    /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(GridCacheAdapter.class, this, "name", name(), "size", size());
     }
@@ -5233,6 +5277,47 @@
     }
 
     /**
+     * Internal callable for global size calculation.
+     */
+    @GridInternal
+    private static class SizeLongJob extends TopologyVersionAwareJob {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** Peek modes. */
+        private final CachePeekMode[] peekModes;
+
+        /**
+         * @param cacheName Cache name.
+         * @param topVer Affinity topology version.
+         * @param peekModes Cache peek modes.
+         */
+        private SizeLongJob(String cacheName, AffinityTopologyVersion topVer, CachePeekMode[] peekModes) {
+            super(cacheName, topVer);
+
+            this.peekModes = peekModes;
+        }
+
+        /** {@inheritDoc} */
+        @Nullable @Override public Object localExecute(@Nullable IgniteInternalCache cache) {
+            if (cache == null)
+                return 0;
+
+            try {
+                return cache.localSizeLong(peekModes);
+            }
+            catch (IgniteCheckedException e) {
+                throw U.convertException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            return S.toString(SizeLongJob.class, this);
+        }
+    }
+
+    /**
      * Holder for last async operation future.
      */
     protected static class FutureHolder {
@@ -5942,6 +6027,71 @@
     }
 
     /**
+     * Size task.
+     */
+    private static class SizeLongTask extends ComputeTaskAdapter<Object, Long> {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** Cache name. */
+        private final String cacheName;
+
+        /** Affinity topology version. */
+        private final AffinityTopologyVersion topVer;
+
+        /** Peek modes. */
+        private final CachePeekMode[] peekModes;
+
+        /**
+         * @param cacheName Cache name.
+         * @param topVer Affinity topology version.
+         * @param peekModes Cache peek modes.
+         */
+        public SizeLongTask(String cacheName, AffinityTopologyVersion topVer, CachePeekMode[] peekModes) {
+            this.cacheName = cacheName;
+            this.topVer = topVer;
+            this.peekModes = peekModes;
+        }
+
+        /** {@inheritDoc} */
+        @Nullable @Override public Map<? extends ComputeJob, ClusterNode> map(List<ClusterNode> subgrid,
+            @Nullable Object arg) throws IgniteException {
+            Map<ComputeJob, ClusterNode> jobs = new HashMap();
+
+            for (ClusterNode node : subgrid)
+                jobs.put(new SizeLongJob(cacheName, topVer, peekModes), node);
+
+            return jobs;
+        }
+
+        /** {@inheritDoc} */
+        @Override public ComputeJobResultPolicy result(ComputeJobResult res, List<ComputeJobResult> rcvd) {
+            IgniteException e = res.getException();
+
+            if (e != null) {
+                if (e instanceof ClusterTopologyException)
+                    return ComputeJobResultPolicy.WAIT;
+
+                throw new IgniteException("Remote job threw exception.", e);
+            }
+
+            return ComputeJobResultPolicy.WAIT;
+        }
+
+        /** {@inheritDoc} */
+        @Nullable @Override public Long reduce(List<ComputeJobResult> results) throws IgniteException {
+            long size = 0;
+
+            for (ComputeJobResult res : results) {
+                if (res != null && res.getException() == null)
+                    size += res.<Long>getData();
+            }
+
+            return size;
+        }
+    }
+
+    /**
      * Clear task.
      */
     private static class ClearTask<K> extends ComputeTaskAdapter<Object, Object> {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMap.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMap.java
index fac704b..1c64387 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMap.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMap.java
@@ -72,7 +72,7 @@
     private static final float DFLT_LOAD_FACTOR = 0.75f;
 
     /** The default concurrency level for this map. */
-    private static final int DFLT_CONCUR_LEVEL = 2048;
+    private static final int DFLT_CONCUR_LEVEL = Runtime.getRuntime().availableProcessors() * 2;
 
     /**
      * The maximum capacity, used if a higher value is implicitly specified by either
@@ -237,6 +237,7 @@
      * @param ctx Cache context.
      * @param initCap the initial capacity. The implementation
      *      performs internal sizing to accommodate this many elements.
+     * @param factory Entry factory.
      * @param loadFactor  the load factor threshold, used to control resizing.
      *      Resizing may be performed when the average number of elements per
      *      bin exceeds this threshold.
@@ -248,8 +249,13 @@
      *      non-positive.
      */
     @SuppressWarnings({"unchecked"})
-    protected GridCacheConcurrentMap(GridCacheContext ctx, int initCap, float loadFactor,
-        int concurrencyLevel) {
+    protected GridCacheConcurrentMap(
+        GridCacheContext ctx,
+        int initCap,
+        GridCacheMapEntryFactory factory,
+        float loadFactor,
+        int concurrencyLevel
+    ) {
         this.ctx = ctx;
 
         if (!(loadFactor > 0) || initCap < 0 || concurrencyLevel <= 0)
@@ -289,6 +295,8 @@
 
         for (int i = 0; i < segs.length; ++i)
             segs[i] = new Segment(cap, loadFactor);
+
+        this.factory = factory;
     }
 
     /**
@@ -298,34 +306,16 @@
      * @param ctx Cache context.
      * @param initCap The implementation performs internal
      *      sizing to accommodate this many elements.
-     * @param loadFactor  the load factor threshold, used to control resizing.
-     *      Resizing may be performed when the average number of elements per
-     *      bin exceeds this threshold.
      * @param factory Entries factory.
      * @throws IllegalArgumentException if the initial capacity of
      *      elements is negative or the load factor is non-positive.
      */
-    public GridCacheConcurrentMap(GridCacheContext ctx,
+    public GridCacheConcurrentMap(
+        GridCacheContext ctx,
         int initCap,
-        float loadFactor,
-        @Nullable GridCacheMapEntryFactory factory) {
-        this(ctx, initCap, loadFactor, DFLT_CONCUR_LEVEL);
-
-        this.factory = factory;
-    }
-
-    /**
-     * Creates a new, empty map with the specified initial capacity,
-     * and with default load factor (0.75) and concurrencyLevel (16).
-     *
-     * @param ctx Cache context.
-     * @param initCap the initial capacity. The implementation
-     *      performs internal sizing to accommodate this many elements.
-     * @throws IllegalArgumentException if the initial capacity of
-     *      elements is negative.
-     */
-    public GridCacheConcurrentMap(GridCacheContext ctx, int initCap) {
-        this(ctx, initCap, DFLT_LOAD_FACTOR, DFLT_CONCUR_LEVEL);
+        @Nullable GridCacheMapEntryFactory factory
+    ) {
+        this(ctx, initCap, factory, DFLT_LOAD_FACTOR, DFLT_CONCUR_LEVEL);
     }
 
     /**
@@ -1439,13 +1429,6 @@
         }
 
         /**
-         * @return Number of reads.
-         */
-        long reads() {
-            return reads.sum();
-        }
-
-        /**
          * @return Header ID.
          */
         int id() {
@@ -1453,21 +1436,6 @@
         }
 
         /**
-         * @return {@code True} if {@code ID} is even.
-         */
-        boolean even() {
-            return id % 2 == 0;
-        }
-
-        /**
-         * @return {@code True} if {@code ID} is odd.
-         */
-        @SuppressWarnings("BadOddness")
-        boolean odd() {
-            return id % 2 == 1;
-        }
-
-        /**
          * @return Table.
          */
         GridCacheMapEntry[] table() {
@@ -2122,9 +2090,7 @@
             it.next();
 
             // Cached value.
-            V val = it.currentValue();
-
-            return val;
+            return it.currentValue();
         }
 
         /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index 73d966a..6e5f958 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -1743,12 +1743,22 @@
      * @param keepPortable Keep portable flag.
      * @return Unwrapped object.
      */
-    @SuppressWarnings("IfMayBeConditional")
     public Object unwrapPortableIfNeeded(Object o, boolean keepPortable) {
         return cacheObjCtx.unwrapPortableIfNeeded(o, keepPortable);
     }
 
     /**
+     * Unwraps object for binary.
+     *
+     * @param o Object to unwrap.
+     * @param keepPortable Keep portable flag.
+     * @return Unwrapped object.
+     */
+    public Object unwrapPortableIfNeeded(Object o, boolean keepPortable, boolean cpy) {
+        return cacheObjCtx.unwrapPortableIfNeeded(o, keepPortable, cpy);
+    }
+
+    /**
      * @return Cache object context.
      */
     public CacheObjectContext cacheObjectContext() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
index 35e8b75..d7f7521 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java
@@ -179,8 +179,12 @@
     /**
      * @param ignore {@code True} to ignore.
      */
-    public void ignoreOwnership(boolean ignore) {
+    public boolean ignoreOwnership(boolean ignore) {
+        boolean old = ignoreOwnership.get();
+
         ignoreOwnership.set(ignore);
+
+        return old;
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java
index afca43b..98579c2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEventManager.java
@@ -39,6 +39,9 @@
  * Cache event manager.
  */
 public class GridCacheEventManager extends GridCacheManagerAdapter {
+    /** Force keep binary flag. Will be set if event notification encountered exception during unmarshalling. */
+    private boolean forceKeepBinary;
+
     /**
      * Adds local event listener.
      *
@@ -262,6 +265,35 @@
                     "(try to increase topology history size configuration property of configured " +
                     "discovery SPI): " + evtNodeId);
 
+            keepPortable = keepPortable || forceKeepBinary;
+
+            Object key0;
+            Object val0;
+            Object oldVal0;
+
+            try {
+                key0 = cctx.cacheObjectContext().unwrapPortableIfNeeded(key, keepPortable, false);
+                val0 = cctx.cacheObjectContext().unwrapPortableIfNeeded(newVal, keepPortable, false);
+                oldVal0 = cctx.cacheObjectContext().unwrapPortableIfNeeded(oldVal, keepPortable, false);
+            }
+            catch (Exception e) {
+                if (!cctx.cacheObjectContext().processor().isPortableEnabled(cctx.config()))
+                    throw e;
+
+                if (log.isDebugEnabled())
+                    log.debug("Failed to unmarshall cache object value for the event notification: " + e);
+
+                if (!forceKeepBinary)
+                    LT.warn(log, null, "Failed to unmarshall cache object value for the event notification " +
+                        "(all further notifications will keep binary object format).");
+
+                forceKeepBinary = true;
+
+                key0 = cctx.cacheObjectContext().unwrapPortableIfNeeded(key, true, false);
+                val0 = cctx.cacheObjectContext().unwrapPortableIfNeeded(newVal, true, false);
+                oldVal0 = cctx.cacheObjectContext().unwrapPortableIfNeeded(oldVal, true, false);
+            }
+
             cctx.gridEvents().record(new CacheEvent(cctx.name(),
                 cctx.localNode(),
                 evtNode,
@@ -269,12 +301,12 @@
                 type,
                 part,
                 cctx.isNear(),
-                cctx.cacheObjectContext().unwrapPortableIfNeeded(key, keepPortable, false),
+                key0,
                 xid,
                 lockId,
-                cctx.cacheObjectContext().unwrapPortableIfNeeded(newVal, keepPortable, false),
+                val0,
                 hasNewVal,
-                cctx.cacheObjectContext().unwrapPortableIfNeeded(oldVal, keepPortable, false),
+                oldVal0,
                 hasOldVal,
                 subjId,
                 cloClsName,
@@ -344,7 +376,9 @@
      * @return {@code True} if event is recordable.
      */
     public boolean isRecordable(int type) {
-        return cctx.userCache() && cctx.gridEvents().isRecordable(type);
+        GridCacheContext cctx0 = cctx;
+
+        return cctx0 != null && cctx0.userCache() && cctx0.gridEvents().isRecordable(type);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java
index 9afbca8..b06526e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java
@@ -28,6 +28,7 @@
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
@@ -67,6 +68,7 @@
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiInClosure;
 import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.lang.IgniteUuid;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
 
@@ -541,7 +543,8 @@
             case 117: {
                 GridNearSingleGetResponse res = (GridNearSingleGetResponse)msg;
 
-                GridPartitionedSingleGetFuture fut = (GridPartitionedSingleGetFuture)ctx.mvcc().future(res.futureId());
+                GridPartitionedSingleGetFuture fut = (GridPartitionedSingleGetFuture)ctx.mvcc()
+                    .future(new IgniteUuid(IgniteUuid.VM_ID, res.futureId()));
 
                 if (fut == null) {
                     if (log.isDebugEnabled())
@@ -1034,6 +1037,9 @@
         catch (IgniteCheckedException e) {
             cacheMsg.onClassError(e);
         }
+        catch (BinaryObjectException e) {
+            cacheMsg.onClassError(new IgniteCheckedException(e));
+        }
         catch (Error e) {
             if (cacheMsg.ignoreClassErrors() && X.hasCause(e, NoClassDefFoundError.class,
                 UnsupportedClassVersionError.class))
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index ac42121..e1f2ade 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -3012,7 +3012,7 @@
      * @return Next entry.
      */
     GridCacheMapEntry next(int segId) {
-        return segId % 2 == 0 ? next0 : next1;
+        return (segId & 1) == 0 ? next0 : next1;
     }
 
     /**
@@ -3022,7 +3022,7 @@
      * @param next Next entry.
      */
     void next(int segId, @Nullable GridCacheMapEntry next) {
-        if (segId % 2 == 0)
+        if ((segId & 1) == 0)
             next0 = next;
         else
             next1 = next;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java
index 61136bf..83e3aa7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java
@@ -84,6 +84,7 @@
     private boolean skipPrepare;
 
     /** Cache ID. */
+    @GridToStringInclude
     protected int cacheId;
 
     /**
@@ -681,6 +682,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(GridCacheMessage.class, this);
+        return S.toString(GridCacheMessage.class, this, "cacheId", cacheId);
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
index 2449df1..dbc6992 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.events.Event;
 import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.NodeStoppingException;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -369,7 +370,7 @@
      * @return Node stop exception.
      */
     private IgniteCheckedException stopError() {
-        return new IgniteCheckedException("Operation has been cancelled (node is stopping).");
+        return new NodeStoppingException("Operation has been cancelled (node is stopping).");
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index 4439eee..6654a15 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -112,7 +112,7 @@
 import org.apache.ignite.lifecycle.LifecycleAware;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.marshaller.jdk.JdkMarshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.spi.IgniteNodeValidationResult;
 import org.jetbrains.annotations.Nullable;
 
@@ -1021,7 +1021,7 @@
         if (cfg.isKeepBinaryInStore() && cfg.isKeepBinaryInStore() != CacheConfiguration.DFLT_KEEP_BINARY_IN_STORE
             && !(ctx.config().getMarshaller() instanceof BinaryMarshaller))
             U.warn(log, "CacheConfiguration.isKeepBinaryInStore() configuration property will be ignored because " +
-                "PortableMarshaller is not used");
+                "BinaryMarshaller is not used");
 
         // Start managers.
         for (GridCacheManager mgr : F.view(cacheCtx.managers(), F.notContains(dhtExcludes(cacheCtx))))
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
index cca6d6a..e82c422 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
@@ -228,6 +228,7 @@
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
     @Override public <K1, V1> GridCacheProxyImpl<K1, V1> keepPortable() {
         if (opCtx != null && opCtx.isKeepBinary())
             return (GridCacheProxyImpl<K1, V1>)this;
@@ -1352,6 +1353,18 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong() {
+        CacheOperationContext prev = gate.enter(opCtx);
+
+        try {
+            return delegate.sizeLong();
+        }
+        finally {
+            gate.leave(prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public int size(CachePeekMode[] peekModes) throws IgniteCheckedException {
         CacheOperationContext prev = gate.enter(opCtx);
 
@@ -1364,6 +1377,18 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong(CachePeekMode[] peekModes) throws IgniteCheckedException {
+        CacheOperationContext prev = gate.enter(opCtx);
+
+        try {
+            return delegate.sizeLong(peekModes);
+        }
+        finally {
+            gate.leave(prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteInternalFuture<Integer> sizeAsync(CachePeekMode[] peekModes) {
         CacheOperationContext prev = gate.enter(opCtx);
 
@@ -1376,6 +1401,18 @@
     }
 
     /** {@inheritDoc} */
+    @Override public IgniteInternalFuture<Long> sizeLongAsync(CachePeekMode[] peekModes) {
+        CacheOperationContext prev = gate.enter(opCtx);
+
+        try {
+            return delegate.sizeLongAsync(peekModes);
+        }
+        finally {
+            gate.leave(prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public int localSize(CachePeekMode[] peekModes) throws IgniteCheckedException {
         CacheOperationContext prev = gate.enter(opCtx);
 
@@ -1388,6 +1425,18 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long localSizeLong(CachePeekMode[] peekModes) throws IgniteCheckedException {
+        CacheOperationContext prev = gate.enter(opCtx);
+
+        try {
+            return delegate.localSizeLong(peekModes);
+        }
+        finally {
+            gate.leave(prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public int nearSize() {
         CacheOperationContext prev = gate.enter(opCtx);
 
@@ -1412,6 +1461,18 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long primarySizeLong() {
+        CacheOperationContext prev = gate.enter(opCtx);
+
+        try {
+            return delegate.primarySizeLong();
+        }
+        finally {
+            gate.leave(prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public void promoteAll(@Nullable Collection<? extends K> keys) throws IgniteCheckedException {
         CacheOperationContext prev = gate.enter(opCtx);
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
index cb36432..8a1cc3f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
@@ -279,6 +279,7 @@
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("deprecation")
     @Nullable @Override public Cache.Entry<K, V> randomEntry() {
         GridKernalContext kctx = ctx.kernalContext();
 
@@ -555,7 +556,7 @@
      * @return Initial iteration cursor.
      */
     @SuppressWarnings("unchecked")
-    private QueryCursor<Cache.Entry<K, V>> queryContinuous(ContinuousQuery qry, boolean loc) {
+    private QueryCursor<Cache.Entry<K, V>> queryContinuous(ContinuousQuery qry, boolean loc, boolean keepBinary) {
         if (qry.getInitialQuery() instanceof ContinuousQuery)
             throw new IgniteException("Initial predicate for continuous query can't be an instance of another " +
                 "continuous query. Use SCAN or SQL query for initial iteration.");
@@ -570,7 +571,8 @@
                 qry.getPageSize(),
                 qry.getTimeInterval(),
                 qry.isAutoUnsubscribe(),
-                loc);
+                loc,
+                keepBinary);
 
             final QueryCursor<Cache.Entry<K, V>> cur =
                 qry.getInitialQuery() != null ? query(qry.getInitialQuery()) : null;
@@ -616,8 +618,11 @@
 
             validate(qry);
 
+            CacheOperationContext opCtxCall = ctx.operationContextPerCall();
+
             if (qry instanceof ContinuousQuery)
-                return (QueryCursor<R>)queryContinuous((ContinuousQuery<K, V>)qry, qry.isLocal());
+                return (QueryCursor<R>)queryContinuous((ContinuousQuery<K, V>)qry, qry.isLocal(),
+                    opCtxCall != null && opCtxCall.isKeepBinary());
 
             if (qry instanceof SqlQuery) {
                 final SqlQuery p = (SqlQuery)qry;
@@ -784,6 +789,30 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong(CachePeekMode... peekModes) throws CacheException {
+        GridCacheGateway<K, V> gate = this.gate;
+
+        CacheOperationContext prev = onEnter(gate, opCtx);
+
+        try {
+            if (isAsync()) {
+                setFuture(delegate.sizeLongAsync(peekModes));
+
+                return 0;
+            }
+            else
+                return delegate.sizeLong(peekModes);
+        }
+        catch (IgniteCheckedException e) {
+            throw cacheException(e);
+        }
+        finally {
+            onLeave(gate, prev);
+        }
+    }
+
+
+    /** {@inheritDoc} */
     @Override public int localSize(CachePeekMode... peekModes) {
         GridCacheGateway<K, V> gate = this.gate;
 
@@ -801,6 +830,23 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long localSizeLong(CachePeekMode... peekModes) {
+        GridCacheGateway<K, V> gate = this.gate;
+
+        CacheOperationContext prev = onEnter(gate, opCtx);
+
+        try {
+            return delegate.localSizeLong(peekModes);
+        }
+        catch (IgniteCheckedException e) {
+            throw cacheException(e);
+        }
+        finally {
+            onLeave(gate, prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public V get(K key) {
         try {
             GridCacheGateway<K, V> gate = this.gate;
@@ -1623,7 +1669,9 @@
         CacheOperationContext prev = onEnter(gate, opCtx);
 
         try {
-            ctx.continuousQueries().executeJCacheQuery(lsnrCfg, false);
+            CacheOperationContext opCtx = ctx.operationContextPerCall();
+
+            ctx.continuousQueries().executeJCacheQuery(lsnrCfg, false, opCtx != null && opCtx.isKeepBinary());
         }
         catch (IgniteCheckedException e) {
             throw cacheException(e);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
index 4155706..1055cf4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
@@ -1342,6 +1342,17 @@
     public int size();
 
     /**
+     * Gets the number of all entries cached on this node as a long value. This method will return the count of
+     * all cache entries and has O(1) complexity on base {@link IgniteInternalCache}. It is essentially the
+     * size of cache key set and is semantically identical to {{@code Cache.keySet().size()}.
+     * <p>
+     * NOTE: this operation is not distributed and returns only the number of entries cached on this node.
+     *
+     * @return Size of cache on this node.
+     */
+    public long sizeLong();
+
+    /**
      * @param peekModes Peek modes.
      * @return Local cache size.
      * @throws IgniteCheckedException If failed.
@@ -1350,6 +1361,13 @@
 
     /**
      * @param peekModes Peek modes.
+     * @return Local cache size as a long value.
+     * @throws IgniteCheckedException If failed.
+     */
+    public long localSizeLong(CachePeekMode[] peekModes) throws IgniteCheckedException;
+
+    /**
+     * @param peekModes Peek modes.
      * @return Global cache size.
      * @throws IgniteCheckedException If failed.
      */
@@ -1357,11 +1375,24 @@
 
     /**
      * @param peekModes Peek modes.
+     * @return Global cache size as a long value.
+     * @throws IgniteCheckedException If failed.
+     */
+    public long sizeLong(CachePeekMode[] peekModes) throws IgniteCheckedException;
+
+    /**
+     * @param peekModes Peek modes.
      * @return Future.
      */
     public IgniteInternalFuture<Integer> sizeAsync(CachePeekMode[] peekModes);
 
     /**
+     * @param peekModes Peek modes.
+     * @return Future.
+     */
+    public IgniteInternalFuture<Long> sizeLongAsync(CachePeekMode[] peekModes);
+
+    /**
      * Gets size of near cache key set. This method will return count of all entries in near
      * cache and has O(1) complexity on base cache projection.
      * <p>
@@ -1386,6 +1417,20 @@
     public int primarySize();
 
     /**
+     * Gets the number of all primary entries cached on this node as a long value. For {@link CacheMode#LOCAL}
+     * non-distributed cache mode, this method is identical to {@link #size()}.
+     * <p>
+     * For {@link CacheMode#PARTITIONED} and {@link CacheMode#REPLICATED} modes, this method will
+     * return number of primary entries cached on this node (excluding any backups). The complexity of
+     * this method is O(P), where P is the total number of partitions.
+     * <p>
+     * NOTE: this operation is not distributed and returns only the number of primary entries cached on this node.
+     *
+     * @return Number of primary entries in cache.
+     */
+    public long primarySizeLong();
+
+    /**
      * This method unswaps cache entries by given keys, if any, from swap storage
      * into memory.
      * <h2 class="header">Transactions</h2>
@@ -1491,7 +1536,7 @@
      * @param subjId Client ID.
      * @return Internal projection.
      */
-    IgniteInternalCache<K, V> forSubjectId(UUID subjId);
+    public IgniteInternalCache<K, V> forSubjectId(UUID subjId);
 
     /**
      * Store DR data.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/affinity/GridCacheAffinityImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/affinity/GridCacheAffinityImpl.java
index 33ab3f4..b9045e9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/affinity/GridCacheAffinityImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/affinity/GridCacheAffinityImpl.java
@@ -24,6 +24,7 @@
 import java.util.Map;
 import java.util.Set;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.affinity.Affinity;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -150,7 +151,7 @@
     @Override public Object affinityKey(K key) {
         A.notNull(key, "key");
 
-        if (key instanceof CacheObject)
+        if (key instanceof CacheObject && !(key instanceof BinaryObject))
             key = ((CacheObject)key).value(cctx.cacheObjectContext(), false);
 
         return cctx.config().getAffinityMapper().affinityKey(key);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/datastructures/CacheDataStructuresManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/datastructures/CacheDataStructuresManager.java
index 431be1e..ec787f8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/datastructures/CacheDataStructuresManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/datastructures/CacheDataStructuresManager.java
@@ -383,7 +383,7 @@
             if (create) {
                 hdr = new GridCacheSetHeader(IgniteUuid.randomUuid(), collocated);
 
-                GridCacheSetHeader old = retryPutIfAbsent(cache, key, hdr);
+                GridCacheSetHeader old = (GridCacheSetHeader)cache.getAndPutIfAbsent(key, hdr);
 
                 if (old != null)
                     hdr = old;
@@ -493,6 +493,12 @@
 
                         continue;
                     }
+                    else if (!pingNodes(nodes)) {
+                        if (log.isDebugEnabled())
+                            log.debug("RemoveSetData job failed and set data node left, will retry: " + e);
+
+                        continue;
+                    }
                     else
                         throw e;
                 }
@@ -510,6 +516,12 @@
 
                         continue;
                     }
+                    else if (!pingNodes(nodes)) {
+                        if (log.isDebugEnabled())
+                            log.debug("RemoveSetData job failed and set data node left, will retry: " + e);
+
+                        continue;
+                    }
                     else
                         throw e;
                 }
@@ -526,6 +538,20 @@
     }
 
     /**
+     * @param nodes Nodes to ping.
+     * @return {@code True} if was able to ping all nodes.
+     * @throws IgniteCheckedException If failed/
+     */
+    private boolean pingNodes(Collection<ClusterNode> nodes) throws IgniteCheckedException {
+        for (ClusterNode node : nodes) {
+            if (!cctx.discovery().pingNode(node.id()))
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
      * @param key Set item key.
      * @param rmv {@code True} if item was removed.
      */
@@ -562,23 +588,6 @@
 
     /**
      * @param cache Cache.
-     * @param key Key.
-     * @param val Value.
-     * @throws IgniteCheckedException If failed.
-     * @return Previous value.
-     */
-    @SuppressWarnings("unchecked")
-    @Nullable private <T> T retryPutIfAbsent(final IgniteInternalCache cache, final Object key, final T val)
-        throws IgniteCheckedException {
-        return DataStructuresProcessor.retry(log, new Callable<T>() {
-            @Nullable @Override public T call() throws Exception {
-                return (T)cache.getAndPutIfAbsent(key, val);
-            }
-        });
-    }
-
-    /**
-     * @param cache Cache.
      * @param keys Keys to remove.
      * @throws IgniteCheckedException If failed.
      */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
index 8537357..7648f10 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
@@ -23,7 +23,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -141,7 +140,8 @@
         if (log.isDebugEnabled())
             log.debug("Processing near get response [nodeId=" + nodeId + ", res=" + res + ']');
 
-        GridPartitionedSingleGetFuture fut = (GridPartitionedSingleGetFuture)ctx.mvcc().future(res.futureId());
+        GridPartitionedSingleGetFuture fut = (GridPartitionedSingleGetFuture)ctx.mvcc()
+            .future(new IgniteUuid(IgniteUuid.VM_ID, res.futureId()));
 
         if (fut == null) {
             if (log.isDebugEnabled())
@@ -593,7 +593,12 @@
 
     /** {@inheritDoc} */
     @Override public int primarySize() {
-        int sum = 0;
+        return (int)primarySizeLong();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long primarySizeLong() {
+        long sum = 0;
 
         AffinityTopologyVersion topVer = ctx.affinity().affinityTopologyVersion();
 
@@ -607,7 +612,7 @@
 
     /**
      * This method is used internally. Use
-     * {@link #getDhtAsync(UUID, long, LinkedHashMap, boolean, AffinityTopologyVersion, UUID, int, IgniteCacheExpiryPolicy, boolean)}
+     * {@link #getDhtAsync(UUID, long, Map, boolean, AffinityTopologyVersion, UUID, int, IgniteCacheExpiryPolicy, boolean)}
      * method instead to retrieve DHT value.
      *
      * @param keys {@inheritDoc}
@@ -685,7 +690,7 @@
      */
     public GridDhtFuture<Collection<GridCacheEntryInfo>> getDhtAsync(UUID reader,
         long msgId,
-        LinkedHashMap<KeyCacheObject, Boolean> keys,
+        Map<KeyCacheObject, Boolean> keys,
         boolean readThrough,
         AffinityTopologyVersion topVer,
         @Nullable UUID subjId,
@@ -720,9 +725,7 @@
 
         final CacheExpiryPolicy expiryPlc = CacheExpiryPolicy.forAccess(ttl);
 
-        LinkedHashMap<KeyCacheObject, Boolean> map = U.newLinkedHashMap(1);
-
-        map.put(req.key(), req.addReader());
+        Map<KeyCacheObject, Boolean> map = Collections.singletonMap(req.key(), req.addReader());
 
         IgniteInternalFuture<Collection<GridCacheEntryInfo>> fut =
             getDhtAsync(nodeId,
@@ -755,7 +758,8 @@
                                 info.key(null);
 
                                 res0 = info;
-                            } else if (req.needVersion())
+                            }
+                            else if (req.needVersion())
                                 res0 = new CacheVersionedValue(info.value(), info.version());
                             else
                                 res0 = info.value();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java
index 6b696b0..626713a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtGetFuture.java
@@ -21,7 +21,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicReference;
@@ -80,7 +79,7 @@
     private GridCacheContext<K, V> cctx;
 
     /** Keys. */
-    private LinkedHashMap<KeyCacheObject, Boolean> keys;
+    private Map<KeyCacheObject, Boolean> keys;
 
     /** Reserved partitions. */
     private Collection<GridDhtLocalPartition> parts = new HashSet<>();
@@ -129,7 +128,7 @@
         GridCacheContext<K, V> cctx,
         long msgId,
         UUID reader,
-        LinkedHashMap<KeyCacheObject, Boolean> keys,
+        Map<KeyCacheObject, Boolean> keys,
         boolean readThrough,
         @Nullable IgniteTxLocalEx tx,
         @NotNull AffinityTopologyVersion topVer,
@@ -207,7 +206,7 @@
     /**
      * @param keys Keys.
      */
-    private void map(final LinkedHashMap<KeyCacheObject, Boolean> keys) {
+    private void map(final Map<KeyCacheObject, Boolean> keys) {
         GridDhtFuture<Object> fut = cctx.dht().dhtPreloader().request(keys.keySet(), topVer);
 
         if (!F.isEmpty(fut.invalidPartitions())) {
@@ -227,7 +226,7 @@
                         onDone(e);
                     }
 
-                    LinkedHashMap<KeyCacheObject, Boolean> mappedKeys = U.newLinkedHashMap(keys.size());
+                    Map<KeyCacheObject, Boolean> mappedKeys = null;
 
                     // Assign keys to primary nodes.
                     for (Map.Entry<KeyCacheObject, Boolean> key : keys.entrySet()) {
@@ -239,14 +238,25 @@
                                     retries = new HashSet<>();
 
                                 retries.add(part);
+
+                                if (mappedKeys == null) {
+                                    mappedKeys = U.newLinkedHashMap(keys.size());
+
+                                    for (Map.Entry<KeyCacheObject, Boolean> key1 : keys.entrySet()) {
+                                        if (key1.getKey() == key.getKey())
+                                            break;
+
+                                        mappedKeys.put(key.getKey(), key1.getValue());
+                                    }
+                                }
                             }
-                            else
+                            else if (mappedKeys != null)
                                 mappedKeys.put(key.getKey(), key.getValue());
                         }
                     }
 
                     // Add new future.
-                    add(getAsync(mappedKeys));
+                    add(getAsync(mappedKeys == null ? keys : mappedKeys));
 
                     // Finish this one.
                     return Collections.emptyList();
@@ -288,8 +298,8 @@
      */
     @SuppressWarnings( {"unchecked", "IfMayBeConditional"})
     private IgniteInternalFuture<Collection<GridCacheEntryInfo>> getAsync(
-        final LinkedHashMap<KeyCacheObject, Boolean> keys)
-    {
+        final Map<KeyCacheObject, Boolean> keys
+    ) {
         if (F.isEmpty(keys))
             return new GridFinishedFuture<Collection<GridCacheEntryInfo>>(
                 Collections.<GridCacheEntryInfo>emptyList());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
index 7792de3..2b5d5a4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.NodeStoppingException;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheEntryPredicate;
@@ -481,7 +482,7 @@
     private void onFailed(boolean dist) {
         undoLocks(dist);
 
-        onComplete(false);
+        onComplete(false, false);
     }
 
     /**
@@ -627,7 +628,7 @@
             err = t;
         }
 
-        onComplete(false);
+        onComplete(false, false);
     }
 
     /**
@@ -690,7 +691,7 @@
     /** {@inheritDoc} */
     @Override public boolean cancel() {
         if (onCancelled())
-            onComplete(false);
+            onComplete(false, false);
 
         return isCancelled();
     }
@@ -720,26 +721,27 @@
                 this.err = err;
         }
 
-        return onComplete(success);
+        return onComplete(success, err instanceof NodeStoppingException);
     }
 
     /**
      * Completeness callback.
      *
      * @param success {@code True} if lock was acquired.
+     * @param stopping {@code True} if node is stopping.
      * @return {@code True} if complete by this operation.
      */
-    private boolean onComplete(boolean success) {
+    private boolean onComplete(boolean success, boolean stopping) {
         if (log.isDebugEnabled())
             log.debug("Received onComplete(..) callback [success=" + success + ", fut=" + this + ']');
 
-        if (!success)
+        if (!success && !stopping)
             undoLocks(true);
 
         if (tx != null)
             cctx.tm().txContext(tx);
 
-        if (err == null)
+        if (err == null && !stopping)
             loadMissingFromStore();
 
         if (super.onDone(success, err)) {
@@ -771,7 +773,7 @@
      */
     public void map() {
         if (F.isEmpty(entries)) {
-            onComplete(true);
+            onComplete(true, false);
 
             return;
         }
@@ -1062,7 +1064,7 @@
 
             timedOut = true;
 
-            onComplete(false);
+            onComplete(false, false);
         }
 
         /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java
index e8ef5d4..9a0d778 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java
@@ -201,9 +201,17 @@
 
             Throwable e = this.err.get();
 
-            if (super.onDone(tx, e != null ? e : err)) {
+            if (e == null && commit)
+                e = this.tx.commitError();
+
+            Throwable finishErr = e != null ? e : err;
+
+            if (super.onDone(tx, finishErr)) {
+                if (finishErr == null)
+                    finishErr = this.tx.commitError();
+
                 // Always send finish reply.
-                this.tx.sendFinishReply(commit, error());
+                this.tx.sendFinishReply(commit, finishErr);
 
                 // Don't forget to clean up.
                 cctx.mvcc().removeFuture(futId);
@@ -474,6 +482,7 @@
         });
 
         return S.toString(GridDhtTxFinishFuture.class, this,
+            "xidVer", tx.xidVersion(),
             "innerFuts", futs,
             "super", super.toString());
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
index 2330a95..534a560 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
@@ -822,7 +822,7 @@
     /**
      * @return {@code True} if transaction is finished on prepare step.
      */
-    protected final boolean commitOnPrepare() {
+    public final boolean commitOnPrepare() {
         return onePhaseCommit() && !near() && !nearOnOriginatingNode;
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
index c55bead..9f1f8a1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
@@ -58,6 +58,7 @@
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.processors.dr.GridDrType;
+import org.apache.ignite.internal.transactions.IgniteTxHeuristicCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException;
 import org.apache.ignite.internal.util.F0;
 import org.apache.ignite.internal.util.GridLeanSet;
@@ -80,8 +81,6 @@
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_OBJECT_LOADED;
-import static org.apache.ignite.internal.managers.communication.GridIoPolicy.SYSTEM_POOL;
-import static org.apache.ignite.internal.managers.communication.GridIoPolicy.UTILITY_CACHE_POOL;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.CREATE;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.DELETE;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.NOOP;
@@ -417,7 +416,7 @@
                 U.error(log, "Failed to get result value for cache entry: " + cached, e);
             }
             catch (GridCacheEntryRemovedException e) {
-                assert false : "Got entry removed exception while holding transactional lock on entry: " + e;
+                assert false : "Got entry removed exception while holding transactional lock on entry [e=" + e + ", cached=" + cached + ']';
             }
         }
     }
@@ -602,13 +601,8 @@
                 if (tx.markFinalizing(IgniteInternalTx.FinalizationStatus.USER_FINISH)) {
                     IgniteInternalFuture<IgniteInternalTx> fut = null;
 
-                    if (prepErr == null)
-                        fut = tx.commitAsync();
-                    else if (!cctx.kernalContext().isStopping())
-                        fut = tx.rollbackAsync();
-
-                    if (fut != null) {
-                        fut.listen(new CIX1<IgniteInternalFuture<IgniteInternalTx>>() {
+                    CIX1<IgniteInternalFuture<IgniteInternalTx>> responseClo =
+                        new CIX1<IgniteInternalFuture<IgniteInternalTx>>() {
                             @Override public void applyx(IgniteInternalFuture<IgniteInternalTx> fut) {
                                 try {
                                     if (replied.compareAndSet(false, true))
@@ -618,8 +612,33 @@
                                     U.error(log, "Failed to send prepare response for transaction: " + tx, e);
                                 }
                             }
-                        });
+                        };
+
+                    if (prepErr == null) {
+                        try {
+                            fut = tx.commitAsync();
+                        }
+                        catch (RuntimeException | Error e) {
+                            Exception hEx = new IgniteTxHeuristicCheckedException("Commit produced a runtime " +
+                                "exception: " + CU.txString(tx), e);
+
+                            res.error(hEx);
+
+                            tx.systemInvalidate(true);
+
+                            fut = tx.rollbackAsync();
+
+                            fut.listen(responseClo);
+
+                            throw e;
+                        }
+
                     }
+                    else if (!cctx.kernalContext().isStopping())
+                        fut = tx.rollbackAsync();
+
+                    if (fut != null)
+                        fut.listen(responseClo);
                 }
             }
             else {
@@ -1187,7 +1206,7 @@
                         assert req.transactionNodes() != null;
 
                         try {
-                            cctx.io().send(nearMapping.node(), req, tx.system() ? UTILITY_CACHE_POOL : SYSTEM_POOL);
+                            cctx.io().send(nearMapping.node(), req, tx.ioPolicy());
                         }
                         catch (ClusterTopologyCheckedException e) {
                             fut.onNodeLeft(e);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java
index e0929ad..85a5759 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java
@@ -279,20 +279,7 @@
     @Override public void addInvalidPartition(GridCacheContext cacheCtx, int part) {
         super.addInvalidPartition(cacheCtx, part);
 
-        Map<IgniteTxKey, IgniteTxEntry> writeMap = txState.writeMap();
-
-        for (Iterator<IgniteTxEntry> it = writeMap.values().iterator(); it.hasNext();) {
-            IgniteTxEntry e = it.next();
-
-            GridCacheEntryEx cached = e.cached();
-
-            if (cached != null) {
-                if (cached.partition() == part)
-                    it.remove();
-            }
-            else if (cacheCtx.affinity().partition(e.key()) == part)
-                it.remove();
-        }
+        txState.invalidPartition(part);
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridNoStorageCacheMap.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridNoStorageCacheMap.java
index ef6612b..c6b969d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridNoStorageCacheMap.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridNoStorageCacheMap.java
@@ -41,7 +41,7 @@
      * @param ctx Cache context.
      */
     public GridNoStorageCacheMap(GridCacheContext ctx) {
-        super(ctx, 0, 0.75f, 1);
+        super(ctx, 0, null, 0.75f, 1);
     }
 
     /** {@inheritDoc} */
@@ -119,4 +119,4 @@
     @Override public String toString() {
         return S.toString(GridNoStorageCacheMap.class, this);
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
index f276cac..99cf210 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
@@ -18,8 +18,9 @@
 package org.apache.ignite.internal.processors.cache.distributed.dht;
 
 import java.util.Collection;
-import java.util.LinkedHashMap;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.IgniteCheckedException;
@@ -198,10 +199,11 @@
             return;
         }
 
-        if (node.isLocal()) {
-            LinkedHashMap<KeyCacheObject, Boolean> map = U.newLinkedHashMap(1);
+        if (isDone())
+            return;
 
-            map.put(key, false);
+        if (node.isLocal()) {
+            Map<KeyCacheObject, Boolean> map = Collections.singletonMap(key, false);
 
             final GridDhtFuture<Collection<GridCacheEntryInfo>> fut = cctx.dht().getDhtAsync(node.id(),
                 -1,
@@ -259,7 +261,7 @@
 
             if (node.version().compareTo(SINGLE_GET_MSG_SINCE) >= 0) {
                 req = new GridNearSingleGetRequest(cctx.cacheId(),
-                    futId,
+                    futId.localId(),
                     key,
                     readThrough,
                     topVer,
@@ -272,9 +274,7 @@
                     cctx.deploymentEnabled());
             }
             else {
-                LinkedHashMap<KeyCacheObject, Boolean> map = U.newLinkedHashMap(1);
-
-                map.put(key, false);
+                Map<KeyCacheObject, Boolean> map = Collections.singletonMap(key, false);
 
                 req = new GridNearGetRequest(
                     cctx.cacheId(),
@@ -323,7 +323,7 @@
             GridDhtCacheAdapter colocated = cctx.dht();
 
             while (true) {
-                GridCacheEntryEx entry;
+                GridCacheEntryEx entry = null;
 
                 try {
                     entry = colocated.context().isSwapOrOffheapEnabled() ? colocated.entryEx(key) :
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
index cd76a56..a49341b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
@@ -724,7 +724,9 @@
     /** {@inheritDoc} */
     @Override public <T> EntryProcessorResult<T> invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object... args)
         throws IgniteCheckedException {
-        EntryProcessorResult<T> res = invokeAsync(key, entryProcessor, args).get();
+        IgniteInternalFuture<EntryProcessorResult<T>> invokeFut = invokeAsync(key, entryProcessor, args);
+
+        EntryProcessorResult<T> res = invokeFut.get();
 
         return res != null ? res : new CacheInvokeResult<T>();
     }
@@ -750,6 +752,10 @@
         Map<? extends K, EntryProcessor> invokeMap =
             Collections.singletonMap(key, (EntryProcessor)entryProcessor);
 
+        CacheOperationContext opCtx = ctx.operationContextPerCall();
+
+        final boolean keepBinary = opCtx != null && opCtx.isKeepBinary();
+
         IgniteInternalFuture<Map<K, EntryProcessorResult<T>>> fut = updateAllAsync0(null,
             invokeMap,
             args,
@@ -768,7 +774,17 @@
                 if (resMap != null) {
                     assert resMap.isEmpty() || resMap.size() == 1 : resMap.size();
 
-                    return resMap.isEmpty() ? null : resMap.values().iterator().next();
+                    EntryProcessorResult<T> res = resMap.isEmpty() ? null : resMap.values().iterator().next();
+
+                    if (res instanceof CacheInvokeResult) {
+                        CacheInvokeResult invokeRes = (CacheInvokeResult)res;
+
+                        if (invokeRes.result() != null)
+                            res = CacheInvokeResult.fromResult((T)ctx.unwrapPortableIfNeeded(invokeRes.result(),
+                                keepBinary, false));
+                    }
+
+                    return res;
                 }
 
                 return null;
@@ -792,7 +808,11 @@
             }
         });
 
-        return updateAllAsync0(null,
+        CacheOperationContext opCtx = ctx.operationContextPerCall();
+
+        final boolean keepBinary = opCtx != null && opCtx.isKeepBinary();
+
+        IgniteInternalFuture<Map<K, EntryProcessorResult<T>>> resFut = updateAllAsync0(null,
             invokeMap,
             args,
             null,
@@ -801,6 +821,30 @@
             false,
             null,
             true);
+
+        return resFut.chain(new CX1<IgniteInternalFuture<Map<K, EntryProcessorResult<T>>>, Map<K, EntryProcessorResult<T>>>() {
+            @Override public Map<K, EntryProcessorResult<T>> applyx(IgniteInternalFuture<Map<K, EntryProcessorResult<T>>> fut) throws IgniteCheckedException {
+                Map<K, EntryProcessorResult<T>> resMap = fut.get();
+
+                if (resMap != null) {
+                    return F.viewReadOnly(resMap, new C1<EntryProcessorResult<T>, EntryProcessorResult<T>>() {
+                        @Override public EntryProcessorResult<T> apply(EntryProcessorResult<T> res) {
+                            if (res instanceof CacheInvokeResult) {
+                                CacheInvokeResult invokeRes = (CacheInvokeResult)res;
+
+                                if (invokeRes.result() != null)
+                                    res = CacheInvokeResult.fromResult((T)ctx.unwrapPortableIfNeeded(invokeRes.result(),
+                                        keepBinary, false));
+                            }
+
+                            return res;
+                        }
+                    });
+                }
+
+                return null;
+            }
+        });
     }
 
     /** {@inheritDoc} */
@@ -1349,7 +1393,7 @@
 
             remap = true;
         }
-        catch (Exception e) {
+        catch (Throwable e) {
             // At least RuntimeException can be thrown by the code above when GridCacheContext is cleaned and there is
             // an attempt to use cleaned resources.
             U.error(log, "Unexpected exception during cache update", e);
@@ -1358,6 +1402,9 @@
 
             completionCb.apply(req, res);
 
+            if (e instanceof Error)
+                throw e;
+
             return;
         }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java
index a8807e1..4f15fa1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java
@@ -647,6 +647,8 @@
 
         prepareMarshalCacheObjects(nearVals, cctx);
 
+        prepareMarshalCacheObjects(prevVals, cctx);
+
         if (forceTransformBackups) {
             // force addition of deployment info for entry processors if P2P is enabled globally.
             if (!addDepInfo && ctx.deploymentEnabled())
@@ -674,6 +676,8 @@
 
         finishUnmarshalCacheObjects(nearVals, cctx, ldr);
 
+        finishUnmarshalCacheObjects(prevVals, cctx, ldr);
+
         if (forceTransformBackups) {
             entryProcessors = unmarshalCollection(entryProcessorsBytes, ctx, ldr);
 
@@ -1049,6 +1053,6 @@
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(GridDhtAtomicUpdateRequest.class, this);
+        return S.toString(GridDhtAtomicUpdateRequest.class, this, "super", super.toString());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java
index 07111a1..513e6e8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java
@@ -324,7 +324,8 @@
         GridCacheReturn ret = (GridCacheReturn)res;
 
         Object retval =
-            res == null ? null : rawRetval ? ret : (this.retval || op == TRANSFORM) ? ret.value() : ret.success();
+            res == null ? null : rawRetval ? ret : (this.retval || op == TRANSFORM) ?
+                cctx.unwrapPortableIfNeeded(ret.value(), keepBinary) : ret.success();
 
         if (op == TRANSFORM && retval == null)
             retval = Collections.emptyMap();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
index 7e6ce89..d3028ca 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
@@ -296,10 +296,6 @@
         GridCacheMvccCandidate cand = cctx.mvcc().explicitLock(threadId, txKey);
 
         if (inTx()) {
-            IgniteTxEntry txEntry = tx.entry(txKey);
-
-            txEntry.cached(entry);
-
             if (cand != null) {
                 if (!tx.implicit())
                     throw new IgniteCheckedException("Cannot access key within transaction if lock is " +
@@ -308,6 +304,10 @@
                     return null;
             }
             else {
+                IgniteTxEntry txEntry = tx.entry(txKey);
+
+                txEntry.cached(entry);
+
                 // Check transaction entries (corresponding tx entries must be enlisted in transaction).
                 cand = new GridCacheMvccCandidate(entry,
                     cctx.localNodeId(),
@@ -977,12 +977,27 @@
     }
 
     /**
+     * @throws IgniteCheckedException If failed.
+     */
+    private void proceedMapping() throws IgniteCheckedException {
+        boolean set = tx != null && cctx.shared().tm().setTxTopologyHint(tx);
+
+        try {
+            proceedMapping0();
+        }
+        finally {
+            if (set)
+                cctx.tm().setTxTopologyHint(null);
+        }
+    }
+
+    /**
      * Gets next near lock mapping and either acquires dht locks locally or sends near lock request to
      * remote primary node.
      *
      * @throws IgniteCheckedException If mapping can not be completed.
      */
-    private void proceedMapping()
+    private void proceedMapping0()
         throws IgniteCheckedException {
         GridNearLockMapping map;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheAdapter.java
index cc9d007..c92e4e8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheAdapter.java
@@ -123,9 +123,9 @@
 
     /** {@inheritDoc} */
     @Override public void onReconnected() {
-        map = new GridCacheConcurrentMap(ctx,
+        map = new GridCacheConcurrentMap(
+            ctx,
             ctx.config().getNearConfiguration().getNearStartSize(),
-            0.75F,
             map.getEntryFactory());
     }
 
@@ -310,11 +310,21 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong() {
+        return nearEntries().size() + dht().sizeLong();
+    }
+
+    /** {@inheritDoc} */
     @Override public int primarySize() {
         return dht().primarySize();
     }
 
     /** {@inheritDoc} */
+    @Override public long primarySizeLong() {
+        return dht().primarySizeLong();
+    }
+
+    /** {@inheritDoc} */
     @Override public int nearSize() {
         return nearEntries().size();
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
index 2ea31d5a..3f61b2f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
@@ -542,9 +542,9 @@
                             add(new GridFinishedFuture<>(Collections.singletonMap(key0, val0)));
                         }
                         else {
-                            K key0 = (K)cctx.unwrapPortableIfNeeded(key, !deserializePortable);
+                            K key0 = (K)cctx.unwrapPortableIfNeeded(key, !deserializePortable, false);
                             V val0 = !skipVals ? 
-                                (V)cctx.unwrapPortableIfNeeded(v, !deserializePortable) : 
+                                (V)cctx.unwrapPortableIfNeeded(v, !deserializePortable, false) :
                                 (V)Boolean.TRUE;
 
                             add(new GridFinishedFuture<>(Collections.singletonMap(key0, val0)));
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java
index 6d60298..0c2451e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java
@@ -22,6 +22,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.UUID;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.GridDirectCollection;
@@ -122,7 +123,7 @@
         IgniteUuid futId,
         IgniteUuid miniId,
         GridCacheVersion ver,
-        LinkedHashMap<KeyCacheObject, Boolean> keys,
+        Map<KeyCacheObject, Boolean> keys,
         boolean readThrough,
         @NotNull AffinityTopologyVersion topVer,
         UUID subjId,
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
index f1f9990..4cb7248 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
@@ -263,13 +263,6 @@
     }
 
     /**
-     * @return {@code True} if commit is synchronous.
-     */
-    private boolean syncCommit() {
-        return tx != null && tx.syncCommit();
-    }
-
-    /**
      * @return {@code True} if rollback is synchronous.
      */
     private boolean syncRollback() {
@@ -1082,13 +1075,28 @@
     }
 
     /**
+     * @throws IgniteCheckedException If failed.
+     */
+    private void proceedMapping() throws IgniteCheckedException {
+        boolean set = tx != null && cctx.shared().tm().setTxTopologyHint(tx);
+
+        try {
+            proceedMapping0();
+        }
+        finally {
+            if (set)
+                cctx.tm().setTxTopologyHint(null);
+        }
+    }
+
+    /**
      * Gets next near lock mapping and either acquires dht locks locally or sends near lock request to
      * remote primary node.
      *
      * @throws IgniteCheckedException If mapping can not be completed.
      */
     @SuppressWarnings("unchecked")
-    private void proceedMapping()
+    private void proceedMapping0()
         throws IgniteCheckedException {
         GridNearLockMapping map;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
index 144070c..f52b3fc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
@@ -39,12 +39,10 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxMapping;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
-import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException;
-import org.apache.ignite.internal.util.GridConcurrentHashSet;
 import org.apache.ignite.internal.util.future.GridCompoundFuture;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -76,7 +74,7 @@
 
     /** */
     @GridToStringExclude
-    private KeyLockFuture keyLockFut = new KeyLockFuture();
+    private KeyLockFuture keyLockFut;
 
     /** */
     @GridToStringExclude
@@ -134,7 +132,8 @@
                     }
                 }
 
-                keyLockFut.onKeyLocked(entry.txKey());
+                if (keyLockFut != null)
+                    keyLockFut.onKeyLocked(entry.txKey());
 
                 return true;
             }
@@ -189,7 +188,8 @@
 
         err.compareAndSet(null, e);
 
-        keyLockFut.onDone(e);
+        if (keyLockFut != null)
+            keyLockFut.onDone(e);
     }
 
     /** {@inheritDoc} */
@@ -210,7 +210,8 @@
         if (err != null) {
             this.err.compareAndSet(null, err);
 
-            keyLockFut.onDone(err);
+            if (keyLockFut != null)
+                keyLockFut.onDone(err);
         }
 
         return onComplete();
@@ -303,9 +304,17 @@
             return;
         }
 
-        prepare(tx.readEntries(), tx.writeEntries(), remap, topLocked);
+        boolean set = cctx.tm().setTxTopologyHint(tx);
 
-        markInitialized();
+        try {
+            prepare(tx.readEntries(), tx.writeEntries(), remap, topLocked);
+
+            markInitialized();
+        }
+        finally {
+            if (set)
+                cctx.tm().setTxTopologyHint(null);
+        }
     }
 
     /**
@@ -335,10 +344,8 @@
         for (IgniteTxEntry read : reads)
             map(read, topVer, mappings, remap, topLocked);
 
-        keyLockFut.onAllKeysAdded();
-
-        if (!remap)
-            add(keyLockFut);
+        if (keyLockFut != null)
+            keyLockFut.onAllKeysAdded();
 
         if (isDone()) {
             if (log.isDebugEnabled())
@@ -535,8 +542,15 @@
             entry.cached(cacheCtx.local().entryEx(entry.key(), topVer));
 
         if (!remap && (cacheCtx.isNear() || cacheCtx.isLocal())) {
-            if (entry.explicitVersion() == null)
+            if (entry.explicitVersion() == null) {
+                if (keyLockFut == null) {
+                    keyLockFut = new KeyLockFuture();
+
+                    add(keyLockFut);
+                }
+
                 keyLockFut.addLockKey(entry.txKey());
+            }
         }
 
         IgniteBiTuple<ClusterNode, Boolean> key = F.t(primary, cacheCtx.isNear());
@@ -854,68 +868,4 @@
             return S.toString(MiniFuture.class, this, "done", isDone(), "cancelled", isCancelled(), "err", error());
         }
     }
-
-    /**
-     * Keys lock future.
-     */
-    private class KeyLockFuture extends GridFutureAdapter<GridNearTxPrepareResponse> {
-        /** */
-        @GridToStringInclude
-        private Collection<IgniteTxKey> lockKeys = new GridConcurrentHashSet<>();
-
-        /** */
-        private volatile boolean allKeysAdded;
-
-        /**
-         * @param key Key to track for locking.
-         */
-        private void addLockKey(IgniteTxKey key) {
-            assert !allKeysAdded;
-
-            lockKeys.add(key);
-        }
-
-        /**
-         * @param key Locked keys.
-         */
-        private void onKeyLocked(IgniteTxKey key) {
-            lockKeys.remove(key);
-
-            checkLocks();
-        }
-
-        /**
-         * Moves future to the ready state.
-         */
-        private void onAllKeysAdded() {
-            allKeysAdded = true;
-
-            checkLocks();
-        }
-
-        /**
-         * @return {@code True} if all locks are owned.
-         */
-        private boolean checkLocks() {
-            boolean locked = lockKeys.isEmpty();
-
-            if (locked && allKeysAdded) {
-                if (log.isDebugEnabled())
-                    log.debug("All locks are acquired for near prepare future: " + this);
-
-                onDone((GridNearTxPrepareResponse)null);
-            }
-            else {
-                if (log.isDebugEnabled())
-                    log.debug("Still waiting for locks [fut=" + this + ", keys=" + lockKeys + ']');
-            }
-
-            return locked;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(KeyLockFuture.class, this, super.toString());
-        }
-    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
index e70e574..2ce14af 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
@@ -40,15 +40,15 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxMapping;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
-import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
 import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException;
-import org.apache.ignite.internal.util.GridConcurrentHashSet;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.C1;
 import org.apache.ignite.internal.util.typedef.CI1;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.P1;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -65,8 +65,8 @@
  */
 public class GridNearOptimisticTxPrepareFuture extends GridNearOptimisticTxPrepareFutureAdapter {
     /** */
-    @GridToStringInclude
-    private Collection<IgniteTxKey> lockKeys = new GridConcurrentHashSet<>();
+    @GridToStringExclude
+    private KeyLockFuture keyLockFut;
 
     /**
      * @param cctx Context.
@@ -84,10 +84,8 @@
             log.debug("Transaction future received owner changed callback: " + entry);
 
         if ((entry.context().isNear() || entry.context().isLocal()) && owner != null && tx.hasWriteKey(entry.txKey())) {
-            lockKeys.remove(entry.txKey());
-
-            // This will check for locks.
-            onDone();
+            if (keyLockFut != null)
+                keyLockFut.onKeyLocked(entry.txKey());
 
             return true;
         }
@@ -151,24 +149,6 @@
         }
     }
 
-    /**
-     * @return {@code True} if all locks are owned.
-     */
-    private boolean checkLocks() {
-        boolean locked = lockKeys.isEmpty();
-
-        if (locked) {
-            if (log.isDebugEnabled())
-                log.debug("All locks are acquired for near prepare future: " + this);
-        }
-        else {
-            if (log.isDebugEnabled())
-                log.debug("Still waiting for locks [fut=" + this + ", keys=" + lockKeys + ']');
-        }
-
-        return locked;
-    }
-
     /** {@inheritDoc} */
     @Override public void onResult(UUID nodeId, GridNearTxPrepareResponse res) {
         if (!isDone()) {
@@ -215,8 +195,7 @@
 
     /** {@inheritDoc} */
     @Override public boolean onDone(IgniteInternalTx t, Throwable err) {
-        // If locks were not acquired yet, delay completion.
-        if (isDone() || (err == null && !checkLocks()))
+        if (isDone())
             return false;
 
         this.err.compareAndSet(null, err);
@@ -320,6 +299,9 @@
             return;
         }
 
+        if (keyLockFut != null)
+            keyLockFut.onAllKeysAdded();
+
         tx.addSingleEntryMapping(mapping, write);
 
         cctx.mvcc().recheckPendingLocks();
@@ -385,6 +367,9 @@
             return;
         }
 
+        if (keyLockFut != null)
+            keyLockFut.onAllKeysAdded();
+
         tx.addEntryMapping(mappings);
 
         cctx.mvcc().recheckPendingLocks();
@@ -420,82 +405,90 @@
         if (isDone())
             return;
 
-        assert !m.empty();
+        boolean set = cctx.tm().setTxTopologyHint(tx);
 
-        final ClusterNode n = m.node();
+        try {
+            assert !m.empty();
 
-        GridNearTxPrepareRequest req = new GridNearTxPrepareRequest(
-            futId,
-            tx.topologyVersion(),
-            tx,
-            null,
-            m.writes(),
-            m.near(),
-            txMapping.transactionNodes(),
-            m.last(),
-            tx.onePhaseCommit(),
-            tx.needReturnValue() && tx.implicit(),
-            tx.implicitSingle(),
-            m.explicitLock(),
-            tx.subjectId(),
-            tx.taskNameHash(),
-            m.clientFirst(),
-            tx.activeCachesDeploymentEnabled());
+            final ClusterNode n = m.node();
 
-        for (IgniteTxEntry txEntry : m.writes()) {
-            if (txEntry.op() == TRANSFORM)
-                req.addDhtVersion(txEntry.txKey(), null);
-        }
+            GridNearTxPrepareRequest req = new GridNearTxPrepareRequest(
+                futId,
+                tx.topologyVersion(),
+                tx,
+                null,
+                m.writes(),
+                m.near(),
+                txMapping.transactionNodes(),
+                m.last(),
+                tx.onePhaseCommit(),
+                tx.needReturnValue() && tx.implicit(),
+                tx.implicitSingle(),
+                m.explicitLock(),
+                tx.subjectId(),
+                tx.taskNameHash(),
+                m.clientFirst(),
+                tx.activeCachesDeploymentEnabled());
 
-        // Must lock near entries separately.
-        if (m.near()) {
-            try {
-                tx.optimisticLockEntries(req.writes());
-
-                tx.userPrepare();
+            for (IgniteTxEntry txEntry : m.writes()) {
+                if (txEntry.op() == TRANSFORM)
+                    req.addDhtVersion(txEntry.txKey(), null);
             }
-            catch (IgniteCheckedException e) {
-                onError(e);
-            }
-        }
 
-        final MiniFuture fut = new MiniFuture(m, mappings);
+            // Must lock near entries separately.
+            if (m.near()) {
+                try {
+                    tx.optimisticLockEntries(req.writes());
 
-        req.miniId(fut.futureId());
-
-        add(fut); // Append new future.
-
-        // If this is the primary node for the keys.
-        if (n.isLocal()) {
-            // At this point, if any new node joined, then it is
-            // waiting for this transaction to complete, so
-            // partition reassignments are not possible here.
-            IgniteInternalFuture<GridNearTxPrepareResponse> prepFut = cctx.tm().txHandler().prepareTx(n.id(), tx, req);
-
-            prepFut.listen(new CI1<IgniteInternalFuture<GridNearTxPrepareResponse>>() {
-                @Override public void apply(IgniteInternalFuture<GridNearTxPrepareResponse> prepFut) {
-                    try {
-                        fut.onResult(n.id(), prepFut.get());
-                    }
-                    catch (IgniteCheckedException e) {
-                        fut.onResult(e);
-                    }
+                    tx.userPrepare();
                 }
-            });
-        }
-        else {
-            try {
-                cctx.io().send(n, req, tx.ioPolicy());
+                catch (IgniteCheckedException e) {
+                    onError(e);
+                }
             }
-            catch (ClusterTopologyCheckedException e) {
-                e.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion()));
 
-                fut.onResult(e);
+            final MiniFuture fut = new MiniFuture(m, mappings);
+
+            req.miniId(fut.futureId());
+
+            add(fut); // Append new future.
+
+            // If this is the primary node for the keys.
+            if (n.isLocal()) {
+                // At this point, if any new node joined, then it is
+                // waiting for this transaction to complete, so
+                // partition reassignments are not possible here.
+                IgniteInternalFuture<GridNearTxPrepareResponse> prepFut = cctx.tm().txHandler().prepareTx(n.id(), tx, req);
+
+                prepFut.listen(new CI1<IgniteInternalFuture<GridNearTxPrepareResponse>>() {
+                    @Override public void apply(IgniteInternalFuture<GridNearTxPrepareResponse> prepFut) {
+                        try {
+                            fut.onResult(n.id(), prepFut.get());
+                        }
+                        catch (IgniteCheckedException e) {
+                            fut.onResult(e);
+                        }
+                    }
+                });
             }
-            catch (IgniteCheckedException e) {
-                fut.onResult(e);
+            else {
+                try {
+                    cctx.io().send(n, req, tx.ioPolicy());
+                }
+                catch (ClusterTopologyCheckedException e) {
+                    e.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion()));
+
+                    fut.onResult(e);
+                }
+                catch (IgniteCheckedException e) {
+                    fut.onResult(e);
+                }
             }
         }
+        finally {
+            if (set)
+                cctx.tm().setTxTopologyHint(null);
+        }
     }
 
     /**
@@ -543,8 +536,15 @@
             entry.cached(cacheCtx.local().entryEx(entry.key(), topVer));
 
         if (cacheCtx.isNear() || cacheCtx.isLocal()) {
-            if (entry.explicitVersion() == null)
-                lockKeys.add(entry.txKey());
+            if (entry.explicitVersion() == null) {
+                if (keyLockFut == null) {
+                    keyLockFut = new KeyLockFuture();
+
+                    add(keyLockFut);
+                }
+
+                keyLockFut.addLockKey(entry.txKey());
+            }
         }
 
         if (cur == null || !cur.node().id().equals(primary.id()) || cur.near() != cacheCtx.isNear()) {
@@ -594,10 +594,15 @@
                     ", loc=" + ((MiniFuture)f).node().isLocal() +
                     ", done=" + f.isDone() + "]";
             }
+        }, new P1<IgniteInternalFuture<GridNearTxPrepareResponse>>() {
+            @Override public boolean apply(IgniteInternalFuture<GridNearTxPrepareResponse> fut) {
+                return isMini(fut);
+            }
         });
 
         return S.toString(GridNearOptimisticTxPrepareFuture.class, this,
             "innerFuts", futs,
+            "keyLockFut", keyLockFut,
             "tx", tx,
             "super", super.toString());
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java
index 6b7244a..5c7553f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java
@@ -17,14 +17,20 @@
 
 package org.apache.ignite.internal.processors.cache.distributed.near;
 
+import java.util.Collection;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
+import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
+import org.apache.ignite.internal.util.GridConcurrentHashSet;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.internal.util.lang.GridPlainRunnable;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.CI1;
+import org.apache.ignite.internal.util.typedef.internal.S;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -157,4 +163,68 @@
      * @param topLocked {@code True} if thread already acquired lock preventing topology change.
      */
     protected abstract void prepare0(boolean remap, boolean topLocked);
+
+    /**
+     * Keys lock future.
+     */
+    protected static class KeyLockFuture extends GridFutureAdapter<GridNearTxPrepareResponse> {
+        /** */
+        @GridToStringInclude
+        private Collection<IgniteTxKey> lockKeys = new GridConcurrentHashSet<>();
+
+        /** */
+        private volatile boolean allKeysAdded;
+
+        /**
+         * @param key Key to track for locking.
+         */
+        protected void addLockKey(IgniteTxKey key) {
+            assert !allKeysAdded;
+
+            lockKeys.add(key);
+        }
+
+        /**
+         * @param key Locked keys.
+         */
+        protected void onKeyLocked(IgniteTxKey key) {
+            lockKeys.remove(key);
+
+            checkLocks();
+        }
+
+        /**
+         * Moves future to the ready state.
+         */
+        protected void onAllKeysAdded() {
+            allKeysAdded = true;
+
+            checkLocks();
+        }
+
+        /**
+         * @return {@code True} if all locks are owned.
+         */
+        private boolean checkLocks() {
+            boolean locked = lockKeys.isEmpty();
+
+            if (locked && allKeysAdded) {
+                if (log.isDebugEnabled())
+                    log.debug("All locks are acquired for near prepare future: " + this);
+
+                onDone((GridNearTxPrepareResponse)null);
+            }
+            else {
+                if (log.isDebugEnabled())
+                    log.debug("Still waiting for locks [fut=" + this + ", keys=" + lockKeys + ']');
+            }
+
+            return locked;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(KeyLockFuture.class, this, super.toString());
+        }
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java
index a506007..aa96720 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java
@@ -27,7 +27,6 @@
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -58,7 +57,7 @@
     public static final int NEED_ENTRY_INFO_FLAG_MASK = 0x10;
 
     /** Future ID. */
-    private IgniteUuid futId;
+    private long futId;
 
     /** */
     private KeyCacheObject key;
@@ -102,7 +101,7 @@
      */
     public GridNearSingleGetRequest(
         int cacheId,
-        IgniteUuid futId,
+        long futId,
         KeyCacheObject key,
         boolean readThrough,
         @NotNull AffinityTopologyVersion topVer,
@@ -114,7 +113,6 @@
         boolean needVer,
         boolean addDepInfo
     ) {
-        assert futId != null;
         assert key != null;
 
         this.cacheId = cacheId;
@@ -149,7 +147,7 @@
     /**
      * @return Future ID.
      */
-    public IgniteUuid futureId() {
+    public long futureId() {
         return futId;
     }
 
@@ -268,7 +266,7 @@
                 reader.incrementState();
 
             case 5:
-                futId = reader.readIgniteUuid("futId");
+                futId = reader.readLong("futId");
 
                 if (!reader.isLastRead())
                     return false;
@@ -340,7 +338,7 @@
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeIgniteUuid("futId", futId))
+                if (!writer.writeLong("futId", futId))
                     return false;
 
                 writer.incrementState();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java
index ba0081c..42ad7ed 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java
@@ -28,7 +28,6 @@
 import org.apache.ignite.internal.processors.cache.GridCacheMessage;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -48,7 +47,7 @@
     public static final int CONTAINS_VAL_FLAG_MASK = 0x2;
 
     /** Future ID. */
-    private IgniteUuid futId;
+    private long futId;
 
     /** */
     private Message res;
@@ -83,14 +82,12 @@
      */
     public GridNearSingleGetResponse(
         int cacheId,
-        IgniteUuid futId,
+        long futId,
         AffinityTopologyVersion topVer,
         @Nullable Message res,
         boolean invalidPartitions,
         boolean addDepInfo
     ) {
-        assert futId != null;
-
         this.cacheId = cacheId;
         this.futId = futId;
         this.topVer = topVer;
@@ -151,7 +148,7 @@
     /**
      * @return Future ID.
      */
-    public IgniteUuid futureId() {
+    public long futureId() {
         return futId;
     }
 
@@ -221,7 +218,7 @@
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeIgniteUuid("futId", futId))
+                if (!writer.writeLong("futId", futId))
                     return false;
 
                 writer.incrementState();
@@ -271,7 +268,7 @@
                 reader.incrementState();
 
             case 5:
-                futId = reader.readIgniteUuid("futId");
+                futId = reader.readLong("futId");
 
                 if (!reader.isLastRead())
                     return false;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
index f76fc96..291c88a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.NodeStoppingException;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
@@ -203,6 +204,9 @@
 
                 boolean marked = tx.setRollbackOnly();
 
+                if (err instanceof NodeStoppingException)
+                    return super.onDone(null, err);
+
                 if (err instanceof IgniteTxRollbackCheckedException) {
                     if (marked) {
                         try {
@@ -241,13 +245,13 @@
                     }
                 }
 
-            if (tx.onePhaseCommit()) {
-                boolean commit = this.commit && err == null;
+                if (tx.onePhaseCommit()) {
+                    boolean commit = this.commit && err == null;
 
-                finishOnePhase(commit);
+                    finishOnePhase(commit);
 
-                tx.tmFinish(commit);
-            }
+                    tx.tmFinish(commit);
+                }
 
                 if (super.onDone(tx0, err)) {
                     if (error() instanceof IgniteTxHeuristicCheckedException) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
index 0ceae20..76bfc46 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.internal.util.typedef.internal.S;
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_LOCKED;
@@ -434,4 +435,9 @@
     @Override protected void offHeapPointer(long valPtr) {
         this.valPtr = valPtr;
     }
+
+    /** {@inheritDoc} */
+    @Override public synchronized String toString() {
+        return S.toString(GridLocalCacheEntry.class, this, super.toString());
+    }
 }
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessor.java
index e4db77c..7ef4b91 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessor.java
@@ -57,10 +57,11 @@
      * @param typeName Type name.
      * @param affKeyFieldName Affinity key field name.
      * @param fieldTypeIds Fields map.
+     * @param isEnum Enum flag.
      * @throws IgniteException In case of error.
      */
     public void updateMetadata(int typeId, String typeName, @Nullable String affKeyFieldName,
-        Map<String, Integer> fieldTypeIds) throws IgniteException;
+        Map<String, Integer> fieldTypeIds, boolean isEnum) throws IgniteException;
 
     /**
      * @param typeId Type ID.
@@ -83,6 +84,14 @@
     public Collection<BinaryType> metadata() throws IgniteException;
 
     /**
+     * @param typeName Type name.
+     * @param ord ordinal.
+     * @return Enum object.
+     * @throws IgniteException If failed.
+     */
+    public BinaryObject buildEnum(String typeName, int ord) throws IgniteException;
+
+    /**
      * @return Portables interface.
      * @throws IgniteException If failed.
      */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessorImpl.java
index 05e9263..5b70f2a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectBinaryProcessorImpl.java
@@ -30,8 +30,10 @@
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
+import org.apache.ignite.internal.portable.BinaryEnumObjectImpl;
 import org.apache.ignite.internal.portable.BinaryMetadata;
 import org.apache.ignite.internal.portable.BinaryMetadataHandler;
+import org.apache.ignite.internal.portable.BinaryObjectEx;
 import org.apache.ignite.internal.portable.BinaryObjectImpl;
 import org.apache.ignite.internal.portable.BinaryObjectOffheapImpl;
 import org.apache.ignite.internal.portable.BinaryTypeImpl;
@@ -62,14 +64,16 @@
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.typedef.C1;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteClosure;
 import org.apache.ignite.marshaller.Marshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
 import sun.misc.Unsafe;
@@ -217,7 +221,16 @@
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Override public void onUtilityCacheStarted() throws IgniteCheckedException {
-        metaDataCache = (IgniteCacheProxy)ctx.cache().jcache(CU.UTILITY_CACHE_NAME).withNoRetries();
+        IgniteCacheProxy<Object, Object> proxy = ctx.cache().jcache(CU.UTILITY_CACHE_NAME);
+
+        boolean old = proxy.context().deploy().ignoreOwnership(true);
+
+        try {
+            metaDataCache = (IgniteCacheProxy)proxy.withNoRetries();
+        }
+        finally {
+            proxy.context().deploy().ignoreOwnership(old);
+        }
 
         if (clientNode) {
             assert !metaDataCache.context().affinityNode();
@@ -381,6 +394,15 @@
             return pArr;
         }
 
+        if (obj instanceof IgniteBiTuple) {
+            IgniteBiTuple tup = (IgniteBiTuple)obj;
+
+            if (obj instanceof T2)
+                return new T2<>(marshalToPortable(tup.get1()), marshalToPortable(tup.get2()));
+
+            return new IgniteBiTuple<>(marshalToPortable(tup.get1()), marshalToPortable(tup.get2()));
+        }
+
         if (obj instanceof Collection) {
             Collection<Object> col = (Collection<Object>)obj;
 
@@ -420,9 +442,9 @@
 
         Object obj0 = portableMarsh.unmarshal(arr, null);
 
-        assert obj0 instanceof BinaryObject;
-
-        ((BinaryObjectImpl)obj0).detachAllowed(true);
+        // Possible if a class has writeObject method.
+        if (obj0 instanceof BinaryObject)
+            ((BinaryObjectImpl)obj0).detachAllowed(true);
 
         return obj0;
     }
@@ -446,8 +468,10 @@
 
     /** {@inheritDoc} */
     @Override public void updateMetadata(int typeId, String typeName, @Nullable String affKeyFieldName,
-        Map<String, Integer> fieldTypeIds) throws BinaryObjectException {
-        portableCtx.updateMetadata(typeId, new BinaryMetadata(typeId, typeName, fieldTypeIds, affKeyFieldName, null));
+        Map<String, Integer> fieldTypeIds, boolean isEnum) throws BinaryObjectException {
+        BinaryMetadata meta = new BinaryMetadata(typeId, typeName, fieldTypeIds, affKeyFieldName, null, isEnum);
+
+        portableCtx.updateMetadata(typeId, meta);
     }
 
     /** {@inheritDoc} */
@@ -534,6 +558,17 @@
     }
 
     /** {@inheritDoc} */
+    @Override public BinaryObject buildEnum(String typeName, int ord) throws IgniteException {
+        typeName = PortableContext.typeName(typeName);
+
+        int typeId = portableCtx.typeId(typeName);
+
+        updateMetadata(typeId, typeName, null, null, true);
+
+        return new BinaryEnumObjectImpl(portableCtx, typeId, null, ord);
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteBinary binary() throws IgniteException {
         return portables;
     }
@@ -575,7 +610,7 @@
         if (obj == null)
             return 0;
 
-        return isPortableObject(obj) ? ((BinaryObject)obj).typeId() : typeId(obj.getClass().getSimpleName());
+        return isPortableObject(obj) ? ((BinaryObjectEx)obj).typeId() : typeId(obj.getClass().getSimpleName());
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectPortableContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectPortableContext.java
index c83c9af..719d0a9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectPortableContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/CacheObjectPortableContext.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache.portable;
 
 import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.cache.CacheDefaultBinaryAffinityKeyMapper;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
 import org.apache.ignite.internal.processors.cache.GridCacheDefaultAffinityKeyMapper;
 
@@ -40,7 +41,7 @@
         boolean storeVal,
         boolean portableEnabled,
         boolean depEnabled) {
-        super(kernalCtx, portableEnabled ? new CacheDefaultPortableAffinityKeyMapper() :
+        super(kernalCtx, portableEnabled ? new CacheDefaultBinaryAffinityKeyMapper() :
             new GridCacheDefaultAffinityKeyMapper(), cpyOnGet, storeVal, depEnabled);
 
         this.portableEnabled = portableEnabled;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/IgniteBinaryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/IgniteBinaryImpl.java
index 72f4d24..7008502 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/IgniteBinaryImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/portable/IgniteBinaryImpl.java
@@ -59,6 +59,7 @@
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
     @Override public <T> T toBinary(@Nullable Object obj) throws BinaryObjectException {
         guard();
 
@@ -95,7 +96,7 @@
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public BinaryType metadata(Class<?> cls) throws BinaryObjectException {
+    @Nullable @Override public BinaryType type(Class<?> cls) throws BinaryObjectException {
         guard();
 
         try {
@@ -107,7 +108,7 @@
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public BinaryType metadata(String typeName) throws BinaryObjectException {
+    @Nullable @Override public BinaryType type(String typeName) throws BinaryObjectException {
         guard();
 
         try {
@@ -119,7 +120,7 @@
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public BinaryType metadata(int typeId) throws BinaryObjectException {
+    @Nullable @Override public BinaryType type(int typeId) throws BinaryObjectException {
         guard();
 
         try {
@@ -131,7 +132,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override public Collection<BinaryType> metadata() throws BinaryObjectException {
+    @Override public Collection<BinaryType> types() throws BinaryObjectException {
         guard();
 
         try {
@@ -142,6 +143,18 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override public BinaryObject buildEnum(String typeName, int ord) {
+        guard();
+
+        try {
+            return proc.buildEnum(typeName, ord);
+        }
+        finally {
+            unguard();
+        }
+    }
+
     /**
      * @return Portable processor.
      */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlQuery.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlQuery.java
index be7bbe9..e56e445 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlQuery.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheSqlQuery.java
@@ -55,6 +55,16 @@
     /** */
     @GridToStringInclude
     @GridDirectTransient
+    private int[] paramIdxs;
+
+    /** */
+    @GridToStringInclude
+    @GridDirectTransient
+    private int paramsSize;
+
+    /** */
+    @GridToStringInclude
+    @GridDirectTransient
     private LinkedHashMap<String, ?> cols;
 
     /** Field kept for backward compatibility. */
@@ -77,6 +87,14 @@
         this.qry = qry;
 
         this.params = F.isEmpty(params) ? EMPTY_PARAMS : params;
+        paramsSize = this.params.length;
+    }
+
+    /**
+     * @param paramIdxs Parameter indexes.
+     */
+    public void parameterIndexes(int[] paramIdxs) {
+        this.paramIdxs = paramIdxs;
     }
 
     /**
@@ -222,4 +240,28 @@
     @Override public byte fieldsCount() {
         return 3;
     }
+
+    /**
+     * @param args Arguments.
+     * @return Copy.
+     */
+    public GridCacheSqlQuery copy(Object[] args) {
+        GridCacheSqlQuery cp = new GridCacheSqlQuery();
+
+        cp.qry = qry;
+        cp.cols = cols;
+        cp.paramIdxs = paramIdxs;
+        cp.paramsSize = paramsSize;
+
+        if (F.isEmpty(args))
+            cp.params = EMPTY_PARAMS;
+        else {
+            cp.params = new Object[paramsSize];
+
+            for (int paramIdx : paramIdxs)
+                cp.params[paramIdx] = args[paramIdx];
+        }
+
+        return cp;
+    }
 }
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
index 4b5fe22..da59c18 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheTwoStepQuery.java
@@ -47,16 +47,27 @@
     /** */
     private Set<String> spaces;
 
+    /** */
+    private final boolean skipMergeTbl;
+
     /**
      * @param spaces All spaces accessed in query.
      * @param rdc Reduce query.
+     * @param skipMergeTbl {@code True} if reduce query can skip merge table creation and
+     *      get data directly from merge index.
      */
-    public GridCacheTwoStepQuery(Set<String> spaces, GridCacheSqlQuery rdc) {
+    public GridCacheTwoStepQuery(Set<String> spaces, GridCacheSqlQuery rdc, boolean skipMergeTbl) {
         assert rdc != null;
 
         this.spaces = spaces;
-
         this.rdc = rdc;
+        this.skipMergeTbl = skipMergeTbl;
+    }
+    /**
+     * @return {@code True} if reduce query can skip merge table creation and get data directly from merge index.
+     */
+    public boolean skipMergeTable() {
+        return skipMergeTbl;
     }
 
     /**
@@ -89,9 +100,12 @@
 
     /**
      * @param qry SQL Query.
+     * @return {@code this}.
      */
-    public void addMapQuery(GridCacheSqlQuery qry) {
+    public GridCacheTwoStepQuery addMapQuery(GridCacheSqlQuery qry) {
         mapQrys.add(qry);
+
+        return this;
     }
 
     /**
@@ -122,6 +136,21 @@
         this.spaces = spaces;
     }
 
+    /**
+     * @param args New arguments to copy with.
+     * @return Copy.
+     */
+    public GridCacheTwoStepQuery copy(Object[] args) {
+        assert !explain;
+
+        GridCacheTwoStepQuery cp = new GridCacheTwoStepQuery(spaces, rdc.copy(args), skipMergeTbl);
+        cp.pageSize = pageSize;
+        for (int i = 0; i < mapQrys.size(); i++)
+            cp.mapQrys.add(mapQrys.get(i).copy(args));
+
+        return cp;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(GridCacheTwoStepQuery.class, this);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java
index 0495e6d..4d3786a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java
@@ -99,6 +99,9 @@
     /** Filtered events. */
     private GridLongList filteredEvts;
 
+    /** Keep binary. */
+    private boolean keepBinary;
+
     /**
      * Required by {@link Message}.
      */
@@ -122,6 +125,7 @@
         KeyCacheObject key,
         @Nullable CacheObject newVal,
         @Nullable CacheObject oldVal,
+        boolean keepBinary,
         int part,
         long updateCntr,
         @Nullable AffinityTopologyVersion topVer) {
@@ -133,6 +137,7 @@
         this.part = part;
         this.updateCntr = updateCntr;
         this.topVer = topVer;
+        this.keepBinary = keepBinary;
     }
 
     /**
@@ -203,6 +208,13 @@
     }
 
     /**
+     * @return Keep binary flag.
+     */
+    boolean isKeepBinary() {
+        return keepBinary;
+    }
+
+    /**
      * @param cntrs Filtered events.
      */
     void filteredEvents(GridLongList cntrs) {
@@ -322,36 +334,42 @@
                 writer.incrementState();
 
             case 4:
-                if (!writer.writeMessage("key", key))
+                if (!writer.writeBoolean("keepBinary", keepBinary))
                     return false;
 
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeMessage("newVal", newVal))
+                if (!writer.writeMessage("key", key))
                     return false;
 
                 writer.incrementState();
 
             case 6:
-                if (!writer.writeMessage("oldVal", oldVal))
+                if (!writer.writeMessage("newVal", newVal))
                     return false;
 
                 writer.incrementState();
 
             case 7:
-                if (!writer.writeInt("part", part))
+                if (!writer.writeMessage("oldVal", oldVal))
                     return false;
 
                 writer.incrementState();
 
             case 8:
-                if (!writer.writeMessage("topVer", topVer))
+                if (!writer.writeInt("part", part))
                     return false;
 
                 writer.incrementState();
 
             case 9:
+                if (!writer.writeMessage("topVer", topVer))
+                    return false;
+
+                writer.incrementState();
+
+            case 10:
                 if (!writer.writeLong("updateCntr", updateCntr))
                     return false;
 
@@ -407,7 +425,7 @@
                 reader.incrementState();
 
             case 4:
-                key = reader.readMessage("key");
+                keepBinary = reader.readBoolean("keepBinary");
 
                 if (!reader.isLastRead())
                     return false;
@@ -415,7 +433,7 @@
                 reader.incrementState();
 
             case 5:
-                newVal = reader.readMessage("newVal");
+                key = reader.readMessage("key");
 
                 if (!reader.isLastRead())
                     return false;
@@ -423,7 +441,7 @@
                 reader.incrementState();
 
             case 6:
-                oldVal = reader.readMessage("oldVal");
+                newVal = reader.readMessage("newVal");
 
                 if (!reader.isLastRead())
                     return false;
@@ -431,7 +449,7 @@
                 reader.incrementState();
 
             case 7:
-                part = reader.readInt("part");
+                oldVal = reader.readMessage("oldVal");
 
                 if (!reader.isLastRead())
                     return false;
@@ -439,7 +457,7 @@
                 reader.incrementState();
 
             case 8:
-                topVer = reader.readMessage("topVer");
+                part = reader.readInt("part");
 
                 if (!reader.isLastRead())
                     return false;
@@ -447,6 +465,14 @@
                 reader.incrementState();
 
             case 9:
+                topVer = reader.readMessage("topVer");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 10:
                 updateCntr = reader.readLong("updateCntr");
 
                 if (!reader.isLastRead())
@@ -461,11 +487,11 @@
 
     /** {@inheritDoc} */
     @Override public byte fieldsCount() {
-        return 10;
+        return 11;
     }
 
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(CacheContinuousQueryEntry.class, this);
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEvent.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEvent.java
index d26be5f..f665339 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEvent.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEvent.java
@@ -59,18 +59,18 @@
     /** {@inheritDoc} */
     @Override
     public K getKey() {
-        return (K)cctx.cacheObjectContext().unwrapPortableIfNeeded(e.key(), true, false);
+        return (K)cctx.cacheObjectContext().unwrapPortableIfNeeded(e.key(), e.isKeepBinary(), false);
     }
 
     /** {@inheritDoc} */
     @Override public V getValue() {
-        return (V)cctx.cacheObjectContext().unwrapPortableIfNeeded(e.value(), true, false);
+        return (V)cctx.cacheObjectContext().unwrapPortableIfNeeded(e.value(), e.isKeepBinary(), false);
     }
 
     /** {@inheritDoc} */
     @Override
     public V getOldValue() {
-        return (V)cctx.cacheObjectContext().unwrapPortableIfNeeded(e.oldValue(), true, false);
+        return (V)cctx.cacheObjectContext().unwrapPortableIfNeeded(e.oldValue(), e.isKeepBinary(), false);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java
index 030ab4a..ad86d65 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java
@@ -81,7 +81,7 @@
 /**
  * Continuous query handler.
  */
-class CacheContinuousQueryHandler<K, V> implements GridContinuousHandler {
+public class CacheContinuousQueryHandler<K, V> implements GridContinuousHandler {
     /** */
     private static final long serialVersionUID = 0L;
 
@@ -128,7 +128,10 @@
     private transient Collection<CacheContinuousQueryEntry> backupQueue;
 
     /** */
-    private boolean localCache;
+    private boolean locCache;
+
+    /** */
+    private transient boolean keepBinary;
 
     /** */
     private transient ConcurrentMap<Integer, PartitionRecovery> rcvs;
@@ -180,7 +183,8 @@
         boolean ignoreExpired,
         int taskHash,
         boolean skipPrimaryCheck,
-        boolean locCache) {
+        boolean locCache,
+        boolean keepBinary) {
         assert topic != null;
         assert locLsnr != null;
 
@@ -195,7 +199,8 @@
         this.ignoreExpired = ignoreExpired;
         this.taskHash = taskHash;
         this.skipPrimaryCheck = skipPrimaryCheck;
-        this.localCache = locCache;
+        this.locCache = locCache;
+        this.keepBinary = keepBinary;
 
         cacheId = CU.cacheId(cacheName);
     }
@@ -216,6 +221,18 @@
     }
 
     /** {@inheritDoc} */
+    @Override public boolean keepBinary() {
+        return keepBinary;
+    }
+
+    /**
+     * @param keepBinary Keep binary flag.
+     */
+    public void keepBinary(boolean keepBinary) {
+        this.keepBinary = keepBinary;
+    }
+
+    /** {@inheritDoc} */
     @Override public String cacheName() {
         return cacheName;
     }
@@ -284,6 +301,11 @@
                 }
             }
 
+            /** {@inheritDoc} */
+            @Override public boolean keepBinary() {
+                return keepBinary;
+            }
+
             @Override public void onEntryUpdated(CacheContinuousQueryEvent<K, V> evt, boolean primary,
                 boolean recordIgniteEvt) {
                 if (ignoreExpired && evt.getEventType() == EventType.EXPIRED)
@@ -317,7 +339,7 @@
 
                     if (primary || skipPrimaryCheck) {
                         if (loc) {
-                            if (!localCache) {
+                            if (!locCache) {
                                 Collection<CacheContinuousQueryEntry> entries = handleEvent(ctx, entry);
 
                                 if (!entries.isEmpty()) {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryListener.java
index 8342acf..86abbef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryListener.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryListener.java
@@ -81,6 +81,11 @@
     public boolean oldValueRequired();
 
     /**
+     * @return Keep binary flag.
+     */
+    public boolean keepBinary();
+
+    /**
      * @return Whether to notify on existing entries.
      */
     public boolean notifyExisting();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java
index b2e7490..0e4cb40 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java
@@ -135,7 +135,7 @@
 
         if (cfgs != null) {
             for (CacheEntryListenerConfiguration cfg : cfgs)
-                executeJCacheQuery(cfg, true);
+                executeJCacheQuery(cfg, true, false);
         }
     }
 
@@ -161,21 +161,23 @@
      */
     public void skipUpdateEvent(KeyCacheObject key, int partId, long updCntr, AffinityTopologyVersion topVer) {
         if (lsnrCnt.get() > 0) {
-            CacheContinuousQueryEntry e0 = new CacheContinuousQueryEntry(
-                cctx.cacheId(),
-                UPDATED,
-                key,
-                null,
-                null,
-                partId,
-                updCntr,
-                topVer);
+            for (CacheContinuousQueryListener lsnr : lsnrs.values()) {
+                CacheContinuousQueryEntry e0 = new CacheContinuousQueryEntry(
+                    cctx.cacheId(),
+                    UPDATED,
+                    key,
+                    null,
+                    null,
+                    lsnr.keepBinary(),
+                    partId,
+                    updCntr,
+                    topVer);
 
-            CacheContinuousQueryEvent evt = new CacheContinuousQueryEvent<>(
+                CacheContinuousQueryEvent evt = new CacheContinuousQueryEvent<>(
                     cctx.kernalContext().cache().jcache(cctx.name()), cctx, e0);
 
-            for (CacheContinuousQueryListener lsnr : lsnrs.values())
                 lsnr.skipUpdateEvent(evt, topVer);
+            }
         }
     }
 
@@ -253,6 +255,7 @@
                 key,
                 newVal,
                 lsnr.oldValueRequired() ? oldVal : null,
+                lsnr.keepBinary(),
                 partId,
                 updateCntr,
                 topVer);
@@ -306,6 +309,7 @@
                     key,
                     null,
                     lsnr.oldValueRequired() ? oldVal : null,
+                    lsnr.keepBinary(),
                     e.partition(),
                     -1,
                     null);
@@ -333,7 +337,8 @@
         int bufSize,
         long timeInterval,
         boolean autoUnsubscribe,
-        boolean loc) throws IgniteCheckedException
+        boolean loc,
+        boolean keepBinary) throws IgniteCheckedException
     {
         return executeQuery0(
             locLsnr,
@@ -346,7 +351,8 @@
             true,
             false,
             true,
-            loc);
+            loc,
+            keepBinary);
     }
 
     /**
@@ -374,7 +380,8 @@
             true,
             false,
             true,
-            loc);
+            loc,
+            false);
     }
 
     /**
@@ -395,9 +402,9 @@
      * @param onStart Whether listener is created on node start.
      * @throws IgniteCheckedException If failed.
      */
-    public void executeJCacheQuery(CacheEntryListenerConfiguration cfg, boolean onStart)
+    public void executeJCacheQuery(CacheEntryListenerConfiguration cfg, boolean onStart, boolean keepBinary)
         throws IgniteCheckedException {
-        JCacheQuery lsnr = new JCacheQuery(cfg, onStart);
+        JCacheQuery lsnr = new JCacheQuery(cfg, onStart, keepBinary);
 
         JCacheQuery old = jCacheLsnrs.putIfAbsent(cfg, lsnr);
 
@@ -471,7 +478,8 @@
         boolean oldValRequired,
         boolean sync,
         boolean ignoreExpired,
-        boolean loc) throws IgniteCheckedException
+        boolean loc,
+        final boolean keepBinary) throws IgniteCheckedException
     {
         cctx.checkSecurity(SecurityPermission.CACHE_READ);
 
@@ -492,7 +500,8 @@
             ignoreExpired,
             taskNameHash,
             skipPrimaryCheck,
-            cctx.isLocal());
+            cctx.isLocal(),
+            keepBinary);
 
         IgnitePredicate<ClusterNode> pred = (loc || cctx.config().getCacheMode() == CacheMode.LOCAL) ?
             F.nodeForNodeId(cctx.localNodeId()) : F.<ClusterNode>alwaysTrue();
@@ -550,6 +559,7 @@
                                     e.key(),
                                     e.rawGet(),
                                     null,
+                                    keepBinary,
                                     0,
                                     -1,
                                     null);
@@ -633,15 +643,19 @@
         private final boolean onStart;
 
         /** */
+        private final boolean keepBinary;
+
+        /** */
         private volatile UUID routineId;
 
         /**
          * @param cfg Listener configuration.
          * @param onStart {@code True} if executed on cache start.
          */
-        private JCacheQuery(CacheEntryListenerConfiguration cfg, boolean onStart) {
+        private JCacheQuery(CacheEntryListenerConfiguration cfg, boolean onStart, boolean keepBinary) {
             this.cfg = cfg;
             this.onStart = onStart;
+            this.keepBinary = keepBinary;
         }
 
         /**
@@ -694,7 +708,8 @@
                 cfg.isOldValueRequired(),
                 cfg.isSynchronous(),
                 false,
-                false);
+                false,
+                keepBinary);
         }
 
         /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/CacheOsStoreManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/CacheOsStoreManager.java
index 29d5155..385b4b1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/CacheOsStoreManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/CacheOsStoreManager.java
@@ -23,7 +23,7 @@
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.processors.platform.PlatformProcessor;
 import org.apache.ignite.internal.processors.platform.cache.store.PlatformCacheStore;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  * Default store manager implementation.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
index 63a4cbe..91ebfd3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
@@ -413,7 +413,7 @@
                 req.transactionNodes(),
                 req.last());
 
-            if (tx.isRollbackOnly()) {
+            if (tx.isRollbackOnly() && !tx.commitOnPrepare()) {
                 try {
                     if (tx.state() != TransactionState.ROLLED_BACK && tx.state() != TransactionState.ROLLING_BACK)
                         tx.rollback();
@@ -713,6 +713,10 @@
             }
         }
         catch (Throwable e) {
+            tx.commitError(e);
+
+            tx.systemInvalidate(true);
+
             U.error(log, "Failed completing transaction [commit=" + req.commit() + ", tx=" + tx + ']', e);
 
             IgniteInternalFuture<IgniteInternalTx> res = null;
@@ -838,7 +842,7 @@
 
         try {
             // Reply back to sender.
-            ctx.io().send(nodeId, res, req.system() ? UTILITY_CACHE_POOL : SYSTEM_POOL);
+            ctx.io().send(nodeId, res, req.policy());
         }
         catch (IgniteCheckedException e) {
             if (e instanceof ClusterTopologyCheckedException) {
@@ -1056,7 +1060,7 @@
             }
 
             try {
-                ctx.io().send(nodeId, res, req.system() ? UTILITY_CACHE_POOL : SYSTEM_POOL);
+                ctx.io().send(nodeId, res, req.policy());
             }
             catch (Throwable e) {
                 // Double-check.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
index 7c6a1d4..f13cff4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
@@ -598,7 +598,7 @@
      * @param entry Cache entry to check.
      */
     private void checkCommitLocks(GridCacheEntryEx entry) {
-        assert ownsLockUnsafe(entry) : "Lock is not owned for commit in PESSIMISTIC mode [entry=" + entry +
+        assert ownsLockUnsafe(entry) : "Lock is not owned for commit [entry=" + entry +
             ", tx=" + this + ']';
     }
 
@@ -2932,6 +2932,8 @@
 
             KeyCacheObject cacheKey = cacheCtx.toCacheKeyObject(key);
 
+            boolean keepBinary = opCtx != null && opCtx.isKeepBinary();
+
             final IgniteInternalFuture<Void> loadFut = enlistWrite(
                 cacheCtx,
                 cacheKey,
@@ -2945,7 +2947,7 @@
                 ret,
                 opCtx != null && opCtx.skipStore(),
                 /*singleRmv*/false,
-                opCtx != null && opCtx.isKeepBinary());
+                keepBinary);
 
             if (pessimistic()) {
                 assert loadFut == null || loadFut.isDone() : loadFut;
@@ -3009,7 +3011,7 @@
                 }
             }
             else
-                return optimisticPutFuture(loadFut, ret);
+                return optimisticPutFuture(cacheCtx, loadFut, ret, keepBinary);
         }
         catch (IgniteCheckedException e) {
             return new GridFinishedFuture(e);
@@ -3099,6 +3101,8 @@
 
             CacheOperationContext opCtx = cacheCtx.operationContextPerCall();
 
+            final boolean keepBinary = opCtx != null && opCtx.isKeepBinary();
+
             final IgniteInternalFuture<Void> loadFut = enlistWrite(
                 cacheCtx,
                 keySet,
@@ -3115,7 +3119,7 @@
                 null,
                 opCtx != null && opCtx.skipStore(),
                 false,
-                opCtx != null && opCtx.isKeepBinary());
+                keepBinary);
 
             if (pessimistic()) {
                 assert loadFut == null || loadFut.isDone() : loadFut;
@@ -3177,7 +3181,7 @@
                 }
             }
             else
-                return optimisticPutFuture(loadFut, ret);
+                return optimisticPutFuture(cacheCtx, loadFut, ret, keepBinary);
         }
         catch (RuntimeException e) {
             onException();
@@ -3191,7 +3195,12 @@
      * @param ret Future result.
      * @return Future.
      */
-    private IgniteInternalFuture optimisticPutFuture(IgniteInternalFuture<Void> loadFut, final GridCacheReturn ret) {
+    private IgniteInternalFuture optimisticPutFuture(
+        final GridCacheContext cacheCtx,
+        IgniteInternalFuture<Void> loadFut,
+        final GridCacheReturn ret,
+        final boolean keepBinary
+    ) {
         if (implicit()) {
             // Should never load missing values for implicit transaction as values will be returned
             // with prepare response, if required.
@@ -3211,7 +3220,8 @@
                         try {
                             txFut.get();
 
-                            return implicitRes;
+                            return new GridCacheReturn(cacheCtx, true, keepBinary,
+                                implicitRes.value(), implicitRes.success());
                         }
                         catch (IgniteCheckedException | RuntimeException e) {
                             rollbackAsync();
@@ -3337,6 +3347,8 @@
         else
             plc = null;
 
+        final boolean keepBinary = opCtx != null && opCtx.isKeepBinary();
+
         final IgniteInternalFuture<Void> loadFut = enlistWrite(
             cacheCtx,
             keys0,
@@ -3353,7 +3365,7 @@
             drMap,
             opCtx != null && opCtx.skipStore(),
             singleRmv,
-            opCtx != null && opCtx.isKeepBinary()
+            keepBinary
         );
 
         if (log.isDebugEnabled())
@@ -3432,7 +3444,8 @@
                         try {
                             txFut.get();
 
-                            return implicitRes;
+                            return new GridCacheReturn(cacheCtx, true, keepBinary,
+                                implicitRes.value(), implicitRes.success());
                         }
                         catch (IgniteCheckedException | RuntimeException e) {
                             rollbackAsync();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
index 421b0e6..243c4cb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
@@ -114,6 +114,9 @@
     /** Committing transactions. */
     private final ThreadLocal<IgniteInternalTx> threadCtx = new ThreadLocal<>();
 
+    /** Transaction which topology version should be used when mapping internal tx. */
+    private final ThreadLocal<IgniteInternalTx> txTopology = new ThreadLocal<>();
+
     /** Per-thread transaction map. */
     private final ConcurrentMap<Long, IgniteInternalTx> threadMap = newMap();
 
@@ -622,7 +625,24 @@
                 return tx;
         }
 
-        return null;
+        return txTopology.get();
+    }
+
+    /**
+     * @param tx Transaction.
+     */
+    public boolean setTxTopologyHint(IgniteInternalTx tx) {
+        if (tx == null)
+            txTopology.remove();
+        else {
+            if (txTopology.get() == null) {
+                txTopology.set(tx);
+
+                return true;
+            }
+        }
+
+        return false;
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteSingleStateImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteSingleStateImpl.java
index 90af517..a68006b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteSingleStateImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteSingleStateImpl.java
@@ -65,15 +65,7 @@
 
     /** {@inheritDoc} */
     @Override public Set<IgniteTxKey> writeSet() {
-        if (entry != null) {
-            HashSet<IgniteTxKey> set = new HashSet<>(3, 0.75f);
-
-            set.add(entry.txKey());
-
-            return set;
-        }
-        else
-            return Collections.<IgniteTxKey>emptySet();
+        return entry != null ? Collections.singleton(entry.txKey()) : Collections.<IgniteTxKey>emptySet();
     }
 
     /** {@inheritDoc} */
@@ -113,6 +105,12 @@
     }
 
     /** {@inheritDoc} */
+    @Override public void invalidPartition(int part) {
+        if (entry != null && entry.context().affinity().partition(entry.key()) == part)
+            entry = null;
+    }
+
+    /** {@inheritDoc} */
     public String toString() {
         return S.toString(IgniteTxRemoteSingleStateImpl.class, this);
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteState.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteState.java
index b8290a1..77fc97e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteState.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteState.java
@@ -31,4 +31,9 @@
      * @param key Entry key.
      */
     public void clearEntry(IgniteTxKey key);
+
+    /**
+     * @param part Partition number.
+     */
+    public void invalidPartition(int part);
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteStateImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteStateImpl.java
index 32bc646..3335b44 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteStateImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteStateImpl.java
@@ -18,8 +18,12 @@
 package org.apache.ignite.internal.processors.cache.transactions;
 
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -118,6 +122,26 @@
     }
 
     /** {@inheritDoc} */
+    @Override public void invalidPartition(int part) {
+        if (writeMap != null) {
+            for (Iterator<IgniteTxEntry> it = writeMap.values().iterator(); it.hasNext();) {
+                IgniteTxEntry e = it.next();
+
+                GridCacheContext cacheCtx = e.context();
+
+                GridCacheEntryEx cached = e.cached();
+
+                if (cached != null) {
+                    if (cached.partition() == part)
+                        it.remove();
+                }
+                else if (cacheCtx.affinity().partition(e.key()) == part)
+                    it.remove();
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
     public String toString() {
         return S.toString(IgniteTxRemoteStateImpl.class, this);
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java
index 5bbc194..80e7b39 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/NoOpBinary.java
@@ -49,22 +49,27 @@
     }
 
     /** {@inheritDoc} */
-    @Override public BinaryType metadata(Class<?> cls) throws BinaryObjectException {
+    @Override public BinaryType type(Class<?> cls) throws BinaryObjectException {
         throw unsupported();
     }
 
     /** {@inheritDoc} */
-    @Override public BinaryType metadata(String typeName) throws BinaryObjectException {
+    @Override public BinaryType type(String typeName) throws BinaryObjectException {
         throw unsupported();
     }
 
     /** {@inheritDoc} */
-    @Override public BinaryType metadata(int typeId) throws BinaryObjectException {
+    @Override public BinaryType type(int typeId) throws BinaryObjectException {
         throw unsupported();
     }
 
     /** {@inheritDoc} */
-    @Override public Collection<BinaryType> metadata() throws BinaryObjectException {
+    @Override public Collection<BinaryType> types() throws BinaryObjectException {
+        throw unsupported();
+    }
+
+    /** {@inheritDoc} */
+    @Override public BinaryObject buildEnum(String typeName, int ord) {
         throw unsupported();
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousHandler.java
index 3d6e266..900835a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousHandler.java
@@ -143,6 +143,11 @@
     public boolean isQuery();
 
     /**
+     * @return {@code True} if Ignite Binary objects should be passed to the listener and filter.
+     */
+    public boolean keepBinary();
+
+    /**
      * @return Cache name if this is a continuous query handler.
      */
     public String cacheName();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java
index 00f5e64..9bc9a38 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java
@@ -55,6 +55,7 @@
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.query.continuous.CacheContinuousQueryHandler;
 import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
 import org.apache.ignite.internal.util.future.GridFinishedFuture;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
@@ -608,7 +609,8 @@
             if (locIncluded && registerHandler(ctx.localNodeId(), routineId, hnd, bufSize, interval, autoUnsubscribe, true))
                 hnd.onListenerRegistered(routineId, ctx);
 
-            ctx.discovery().sendCustomEvent(new StartRoutineDiscoveryMessage(routineId, reqData));
+            ctx.discovery().sendCustomEvent(new StartRoutineDiscoveryMessage(routineId, reqData,
+                reqData.handler().keepBinary()));
         }
         catch (IgniteCheckedException e) {
             startFuts.remove(routineId);
@@ -818,6 +820,12 @@
 
         GridContinuousHandler hnd = data.handler();
 
+        if (req.keepBinary()) {
+            assert hnd instanceof CacheContinuousQueryHandler;
+
+            ((CacheContinuousQueryHandler)hnd).keepBinary(true);
+        }
+
         IgniteCheckedException err = null;
 
         try {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java
index 82c0377..ff037d4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRoutineDiscoveryMessage.java
@@ -40,14 +40,18 @@
     /** */
     private Map<Integer, Long> updateCntrs;
 
+    /** Keep binary flag. */
+    private boolean keepBinary;
+
     /**
      * @param routineId Routine id.
      * @param startReqData Start request data.
      */
-    public StartRoutineDiscoveryMessage(UUID routineId, StartRequestData startReqData) {
+    public StartRoutineDiscoveryMessage(UUID routineId, StartRequestData startReqData, boolean keepBinary) {
         super(routineId);
 
         this.startReqData = startReqData;
+        this.keepBinary = keepBinary;
     }
 
     /**
@@ -88,6 +92,13 @@
         return errs;
     }
 
+    /**
+     * @return {@code True} if keep binary flag was set on continuous handler.
+     */
+    public boolean keepBinary() {
+        return keepBinary;
+    }
+
     /** {@inheritDoc} */
     @Override public boolean isMutable() {
         return true;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java
index 23d64cf..998bd92 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java
@@ -973,7 +973,7 @@
 
         IgniteOutClosureX<GridCacheQueueHeader> rmv = new IgniteOutClosureX<GridCacheQueueHeader>() {
             @Override public GridCacheQueueHeader applyx() throws IgniteCheckedException {
-                return (GridCacheQueueHeader)retryRemove(cctx.cache(), new GridCacheQueueHeaderKey(name));
+                return (GridCacheQueueHeader)cctx.cache().getAndRemove(new GridCacheQueueHeaderKey(name));
             }
         };
 
@@ -1569,7 +1569,7 @@
 
         IgniteOutClosureX<GridCacheSetHeader> rmv = new IgniteOutClosureX<GridCacheSetHeader>() {
             @Override public GridCacheSetHeader applyx() throws IgniteCheckedException {
-                return (GridCacheSetHeader)retryRemove(cctx.cache(), new GridCacheSetHeaderKey(name));
+                return (GridCacheSetHeader)cctx.cache().getAndRemove(new GridCacheSetHeaderKey(name));
             }
         };
 
@@ -1583,22 +1583,6 @@
     }
 
     /**
-     * @param cache Cache.
-     * @param key Key to remove.
-     * @throws IgniteCheckedException If failed.
-     * @return Removed value.
-     */
-    @SuppressWarnings("unchecked")
-    @Nullable private <T> T retryRemove(final IgniteInternalCache cache, final Object key)
-        throws IgniteCheckedException {
-        return retry(log, new Callable<T>() {
-            @Nullable @Override public T call() throws Exception {
-                return (T)cache.getAndRemove(key);
-            }
-        });
-    }
-
-    /**
      * @param log Logger.
      * @param call Callable.
      * @return Callable result.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheInternalKeyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheInternalKeyImpl.java
index ff07754..6031f5e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheInternalKeyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheInternalKeyImpl.java
@@ -34,6 +34,7 @@
     private static final long serialVersionUID = 0L;
 
     /** Name of cache data structure. */
+    @AffinityKeyMapped
     private String name;
 
     /**
@@ -55,7 +56,6 @@
     }
 
     /** {@inheritDoc} */
-    @AffinityKeyMapped
     @Override public String name() {
         return name;
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
index 9a7f0df..71f42e2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformContextImpl.java
@@ -69,7 +69,6 @@
 import org.apache.ignite.internal.processors.platform.utils.PlatformReaderClosure;
 import org.apache.ignite.internal.processors.platform.utils.PlatformUtils;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.T4;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.jetbrains.annotations.Nullable;
 
@@ -177,7 +176,7 @@
     /** {@inheritDoc} */
     @Override public BinaryRawReaderEx reader(PlatformInputStream in) {
         // TODO: IGNITE-1272 - Is class loader needed here?
-        return new BinaryReaderExImpl(marsh.context(), in, null);
+        return new BinaryReaderExImpl(marsh.context(), in, null, null, true);
     }
 
     /** {@inheritDoc} */
@@ -341,9 +340,9 @@
     /** {@inheritDoc} */
     @SuppressWarnings("ConstantConditions")
     @Override public void processMetadata(BinaryRawReaderEx reader) {
-        Collection<T4<Integer, String, String, Map<String, Integer>>> metas = PlatformUtils.readCollection(reader,
-            new PlatformReaderClosure<T4<Integer, String, String, Map<String, Integer>>>() {
-                @Override public T4<Integer, String, String, Map<String, Integer>> read(BinaryRawReaderEx reader) {
+        Collection<Metadata> metas = PlatformUtils.readCollection(reader,
+            new PlatformReaderClosure<Metadata>() {
+                @Override public Metadata read(BinaryRawReaderEx reader) {
                     int typeId = reader.readInt();
                     String typeName = reader.readString();
                     String affKey = reader.readString();
@@ -355,13 +354,15 @@
                             }
                         });
 
-                    return new T4<>(typeId, typeName, affKey, fields);
+                    boolean isEnum = reader.readBoolean();
+
+                    return new Metadata(typeId, typeName, affKey, fields, isEnum);
                 }
             }
         );
 
-        for (T4<Integer, String, String, Map<String, Integer>> meta : metas)
-            cacheObjProc.updateMetadata(meta.get1(), meta.get2(), meta.get3(), meta.get4());
+        for (Metadata meta : metas)
+            cacheObjProc.updateMetadata(meta.typeId, meta.typeName, meta.affKey, meta.fields, meta.isEnum);
     }
 
     /** {@inheritDoc} */
@@ -398,6 +399,7 @@
             writer.writeString(meta.typeName());
             writer.writeString(meta.affinityKeyFieldName());
             writer.writeMap(fields);
+            writer.writeBoolean(meta.isEnum());
         }
     }
 
@@ -615,4 +617,41 @@
     @Override public PlatformClusterNodeFilter createClusterNodeFilter(Object filter) {
         return new PlatformClusterNodeFilterImpl(filter, this);
     }
+
+    /**
+     * Metadata holder.
+     */
+    private static class Metadata {
+        /** Type ID. */
+        private final int typeId;
+
+        /** Type name. */
+        private final String typeName;
+
+        /** Affinity key. */
+        private final String affKey;
+
+        /** Fields map. */
+        private final Map<String, Integer> fields;
+
+        /** Enum flag. */
+        private final boolean isEnum;
+
+        /**
+         * Constructor.
+         *
+         * @param typeId Type ID.
+         * @param typeName Type name.
+         * @param affKey Affinity key.
+         * @param fields Fields.
+         * @param isEnum Enum flag.
+         */
+        public Metadata(int typeId, String typeName, String affKey, Map<String, Integer> fields, boolean isEnum) {
+            this.typeId = typeId;
+            this.typeName = typeName;
+            this.affKey = affKey;
+            this.fields = fields;
+            this.isEnum = isEnum;
+        }
+    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cpp/PlatformCppConfigurationClosure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cpp/PlatformCppConfigurationClosure.java
index b53cc46..4bd311b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cpp/PlatformCppConfigurationClosure.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cpp/PlatformCppConfigurationClosure.java
@@ -26,7 +26,7 @@
 import org.apache.ignite.internal.processors.platform.memory.PlatformMemoryManagerImpl;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.Marshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.platform.cpp.PlatformCppConfiguration;
 
 import java.util.Collections;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java
index a0c5a0b..c506a35 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/dotnet/PlatformDotNetConfigurationClosure.java
@@ -38,7 +38,7 @@
 import org.apache.ignite.lifecycle.LifecycleBean;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.platform.dotnet.PlatformDotNetConfiguration;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.platform.dotnet.PlatformDotNetLifecycleBean;
 
 import java.util.ArrayList;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/transactions/PlatformTransactions.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/transactions/PlatformTransactions.java
index 5f5f5c3..d97e071 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/transactions/PlatformTransactions.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/transactions/PlatformTransactions.java
@@ -236,8 +236,8 @@
             case OP_CACHE_CONFIG_PARAMETERS:
                 TransactionConfiguration txCfg = platformCtx.kernalContext().config().getTransactionConfiguration();
 
-                writer.writeEnum(txCfg.getDefaultTxConcurrency());
-                writer.writeEnum(txCfg.getDefaultTxIsolation());
+                writer.writeInt(txCfg.getDefaultTxConcurrency().ordinal());
+                writer.writeInt(txCfg.getDefaultTxIsolation().ordinal());
                 writer.writeLong(txCfg.getDefaultTxTimeout());
 
                 break;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
index 14c040c..6572764 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
@@ -787,6 +787,7 @@
                     writer.writeString(typ.getSerializer());
                     writer.writeString(typ.getAffinityKeyFieldName());
                     writer.writeObject(typ.getKeepDeserialized());
+                    writer.writeBoolean(typ.isEnum());
                 }
             });
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index d0eeeb1..64f2415 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -222,6 +222,14 @@
                             desc.keyClass(Object.class);
                     }
                     else {
+                        if (keyCls == null)
+                            throw new IgniteCheckedException("Failed to find key class in the node classpath " +
+                                "(use default marshaller to enable binary objects): " + qryEntity.getKeyType());
+
+                        if (valCls == null)
+                            throw new IgniteCheckedException("Failed to find value class in the node classpath " +
+                                "(use default marshaller to enable binary objects) : " + qryEntity.getValueType());
+
                         desc.valueClass(valCls);
                         desc.keyClass(keyCls);
                     }
@@ -1540,26 +1548,42 @@
 
             String alias = aliases.get(fullName.toString());
 
-            ClassProperty tmp;
+            StringBuilder bld = new StringBuilder("get");
+
+            bld.append(prop);
+
+            bld.setCharAt(3, Character.toUpperCase(bld.charAt(3)));
+
+            ClassProperty tmp = null;
 
             try {
-                StringBuilder bld = new StringBuilder("get");
-
-                bld.append(prop);
-
-                bld.setCharAt(3, Character.toUpperCase(bld.charAt(3)));
-
                 tmp = new ClassProperty(cls.getMethod(bld.toString()), key, alias);
             }
             catch (NoSuchMethodException ignore) {
+                // No-op.
+            }
+
+            if (tmp == null) {
                 try {
                     tmp = new ClassProperty(cls.getDeclaredField(prop), key, alias);
                 }
                 catch (NoSuchFieldException ignored) {
-                    return null;
+                    // No-op.
                 }
             }
 
+            if (tmp == null) {
+                try {
+                    tmp = new ClassProperty(cls.getMethod(prop), key, alias);
+                }
+                catch (NoSuchMethodException ignored) {
+                    // No-op.
+                }
+            }
+
+            if (tmp == null)
+                return null;
+
             tmp.parent(res);
 
             cls = tmp.type();
@@ -1672,34 +1696,9 @@
     }
 
     /**
-     *
-     */
-    private abstract static class Property {
-        /**
-         * Gets this property value from the given object.
-         *
-         * @param key Key.
-         * @param val Value.
-         * @return Property value.
-         * @throws IgniteCheckedException If failed.
-         */
-        public abstract Object value(Object key, Object val) throws IgniteCheckedException;
-
-        /**
-         * @return Property name.
-         */
-        public abstract String name();
-
-        /**
-         * @return Class member type.
-         */
-        public abstract Class<?> type();
-    }
-
-    /**
      * Description of type property.
      */
-    private static class ClassProperty extends Property {
+    private static class ClassProperty extends GridQueryProperty {
         /** */
         private final Member member;
 
@@ -1794,7 +1793,7 @@
     /**
      *
      */
-    private class PortableProperty extends Property {
+    private class PortableProperty extends GridQueryProperty {
         /** Property name. */
         private String propName;
 
@@ -1938,7 +1937,7 @@
 
         /** */
         @GridToStringExclude
-        private final Map<String, Property> props = new HashMap<>();
+        private final Map<String, GridQueryProperty> props = new HashMap<>();
 
         /** */
         @GridToStringInclude
@@ -1993,11 +1992,16 @@
         }
 
         /** {@inheritDoc} */
+        @Override public GridQueryProperty property(String name) {
+            return props.get(name);
+        }
+
+        /** {@inheritDoc} */
         @SuppressWarnings("unchecked")
         @Override public <T> T value(String field, Object key, Object val) throws IgniteCheckedException {
             assert field != null;
 
-            Property prop = props.get(field);
+            GridQueryProperty prop = props.get(field);
 
             if (prop == null)
                 throw new IgniteCheckedException("Failed to find field '" + field + "' in type '" + name + "'.");
@@ -2096,7 +2100,7 @@
          * @param failOnDuplicate Fail on duplicate flag.
          * @throws IgniteCheckedException In case of error.
          */
-        public void addProperty(Property prop, boolean failOnDuplicate) throws IgniteCheckedException {
+        public void addProperty(GridQueryProperty prop, boolean failOnDuplicate) throws IgniteCheckedException {
             String name = prop.name();
 
             if (props.put(name, prop) != null && failOnDuplicate)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java
new file mode 100644
index 0000000..d623d25
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProperty.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.query;
+
+import org.apache.ignite.IgniteCheckedException;
+
+/**
+ * Description and access method for query entity field.
+ */
+public abstract class GridQueryProperty {
+    /**
+     * Gets this property value from the given object.
+     *
+     * @param key Key.
+     * @param val Value.
+     * @return Property value.
+     * @throws IgniteCheckedException If failed.
+     */
+    public abstract Object value(Object key, Object val) throws IgniteCheckedException;
+
+    /**
+     * @return Property name.
+     */
+    public abstract String name();
+
+    /**
+     * @return Class member type.
+     */
+    public abstract Class<?> type();
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
index b05e1d8..45919ef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryTypeDescriptor.java
@@ -50,6 +50,12 @@
     public <T> T value(String field, Object key, Object val) throws IgniteCheckedException;
 
     /**
+     * @param name Property name.
+     * @return Property.
+     */
+    public GridQueryProperty property(String name);
+
+    /**
      * Gets indexes for this type.
      *
      * @return Indexes for this type.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridCompoundFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridCompoundFuture.java
index 5f0d411..4b2461e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridCompoundFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridCompoundFuture.java
@@ -25,6 +25,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.C1;
 import org.apache.ignite.internal.util.typedef.F;
@@ -55,6 +56,10 @@
     /** Futures. */
     protected final ArrayList<IgniteInternalFuture<T>> futs = new ArrayList<>();
 
+    /** */
+    @GridToStringExclude
+    private final Listener lsnr = new Listener();
+
     /** Reducer. */
     @GridToStringInclude
     private IgniteReducer<T, R> rdc;
@@ -201,7 +206,7 @@
             futs.add(fut);
         }
 
-        fut.listen(new Listener());
+        fut.listen(lsnr);
 
         if (isCancelled()) {
             try {
@@ -418,7 +423,7 @@
 
         /** {@inheritDoc} */
         @Override public String toString() {
-            return "Compound future listener: " + GridCompoundFuture.this;
+            return "Compound future listener []";
         }
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java
index 0f65d33..a1720d5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/future/GridFutureAdapter.java
@@ -494,4 +494,4 @@
             return "ChainFuture [orig=" + fut + ", doneCb=" + doneCb + ']';
         }
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheConfiguration.java
index 073ad22..69eb311 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheConfiguration.java
@@ -138,7 +138,7 @@
         maxConcurrentAsyncOps = ccfg.getMaxConcurrentAsyncOperations();
         memoryMode = ccfg.getMemoryMode();
         interceptor = compactClass(ccfg.getInterceptor());
-        typeMeta = VisorCacheTypeMetadata.list(ccfg.getTypeMetadata());
+        typeMeta = VisorCacheTypeMetadata.list(ccfg.getQueryEntities(), ccfg.getCacheStoreFactory(), ccfg.getTypeMetadata());
         statisticsEnabled = ccfg.isStatisticsEnabled();
         mgmtEnabled = ccfg.isManagementEnabled();
         ldrFactory = compactClass(ccfg.getCacheLoaderFactory());
@@ -350,4 +350,4 @@
     @Override public String toString() {
         return S.toString(VisorCacheConfiguration.class, this);
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeFieldMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeFieldMetadata.java
index c21354b..323e536 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeFieldMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeFieldMetadata.java
@@ -45,14 +45,30 @@
      * @return Data transfer object for given cache field metadata.
      */
     public static VisorCacheTypeFieldMetadata from(CacheTypeFieldMetadata f) {
-        VisorCacheTypeFieldMetadata fieldMetadata = new VisorCacheTypeFieldMetadata();
+        return new VisorCacheTypeFieldMetadata(f.getDatabaseName(), f.getDatabaseType(),
+            f.getJavaName(), U.compact(f.getJavaType().getName()));
+    }
 
-        fieldMetadata.dbName = f.getDatabaseName();
-        fieldMetadata.dbType = f.getDatabaseType();
-        fieldMetadata.javaName = f.getJavaName();
-        fieldMetadata.javaType = U.compact(f.getJavaType().getName());
+    /**
+     * Empty constructor.
+     */
+    public VisorCacheTypeFieldMetadata() {
+        // No-op.
+    }
 
-        return fieldMetadata;
+    /**
+     * Full constructor.
+     *
+     * @param dbName Column name in database.
+     * @param dbType Column JDBC type in database.
+     * @param javaName Field name in java object.
+     * @param javaType Corresponding java type.
+     */
+    public VisorCacheTypeFieldMetadata(String dbName, int dbType, String javaName, String javaType) {
+        this.dbName = dbName;
+        this.dbType = dbType;
+        this.javaName = javaName;
+        this.javaType = javaType;
     }
 
     /**
@@ -82,4 +98,4 @@
     public String javaType() {
         return javaType;
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeMetadata.java
index 2a00ec1..ec7a114 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheTypeMetadata.java
@@ -25,10 +25,17 @@
 import java.util.Map;
 import org.apache.ignite.cache.CacheTypeFieldMetadata;
 import org.apache.ignite.cache.CacheTypeMetadata;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory;
+import org.apache.ignite.cache.store.jdbc.JdbcType;
+import org.apache.ignite.cache.store.jdbc.JdbcTypeField;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
 
+import javax.cache.configuration.Factory;
+
 /**
  * Data transfer object for {@link CacheTypeMetadata}.
  */
@@ -77,19 +84,129 @@
     private Map<String, LinkedHashMap<String, IgniteBiTuple<String, Boolean>>> grps;
 
     /**
+     * @param qryEntities Collection of query entities.
+     * @param factory Store factory to extract JDBC types info.
      * @param types Cache types metadata configurations.
      * @return Data transfer object for cache type metadata configurations.
      */
-    public static Collection<VisorCacheTypeMetadata> list(Collection<CacheTypeMetadata> types) {
-        if (types == null)
-            return Collections.emptyList();
+    public static Collection<VisorCacheTypeMetadata> list(Collection<QueryEntity> qryEntities, Factory factory,
+        Collection<CacheTypeMetadata> types) {
+        final Collection<VisorCacheTypeMetadata> metas = new ArrayList<>();
 
-        final Collection<VisorCacheTypeMetadata> cfgs = new ArrayList<>(types.size());
+        Map<String, VisorCacheTypeMetadata> metaMap =
+                U.newHashMap(qryEntities != null ? qryEntities.size() : 0);
 
-        for (CacheTypeMetadata type : types)
-            cfgs.add(from(type));
+        // Add query entries.
+        if (qryEntities != null)
+            for (QueryEntity qryEntity : qryEntities) {
+                VisorCacheTypeMetadata meta = from(qryEntity);
 
-        return cfgs;
+                metas.add(meta);
+
+                metaMap.put(meta.keyType, meta);
+            }
+
+        // Add JDBC types.
+        if (factory != null && factory instanceof CacheJdbcPojoStoreFactory) {
+             CacheJdbcPojoStoreFactory jdbcFactory = (CacheJdbcPojoStoreFactory) factory;
+
+            for (JdbcType jdbcType : jdbcFactory.getTypes()) {
+                VisorCacheTypeMetadata meta = metaMap.get(jdbcType.getKeyType());
+
+                boolean notFound = meta == null;
+
+                if (notFound) {
+                    meta = new VisorCacheTypeMetadata();
+
+                    meta.keyType = jdbcType.getKeyType();
+                    meta.valType = jdbcType.getValueType();
+
+                    meta.qryFlds = Collections.emptyMap();
+                    meta.ascFlds = Collections.emptyMap();
+                    meta.descFlds = Collections.emptyMap();
+                    meta.txtFlds = Collections.emptyList();
+                    meta.grps = Collections.emptyMap();
+                }
+
+                meta.dbSchema = jdbcType.getDatabaseSchema();
+                meta.dbTbl = jdbcType.getDatabaseTable();
+
+                JdbcTypeField[] keyFields = jdbcType.getKeyFields();
+
+                meta.keyFields = new ArrayList<>(keyFields.length);
+
+                for (JdbcTypeField fld : keyFields)
+                    meta.keyFields.add(new VisorCacheTypeFieldMetadata(
+                        fld.getDatabaseFieldName(), fld.getDatabaseFieldType(),
+                        fld.getDatabaseFieldName(), U.compact(fld.getJavaFieldType().getName())));
+
+                JdbcTypeField[] valFields = jdbcType.getValueFields();
+
+                meta.valFields = new ArrayList<>(valFields.length);
+
+                for (JdbcTypeField fld : valFields)
+                    meta.valFields.add(new VisorCacheTypeFieldMetadata(
+                            fld.getDatabaseFieldName(), fld.getDatabaseFieldType(),
+                            fld.getDatabaseFieldName(), U.compact(fld.getJavaFieldType().getName())));
+
+                if (notFound)
+                    metas.add(meta);
+            }
+        }
+
+        // Add old deprecated CacheTypeMetadata for compatibility.
+        if (types != null)
+            for (CacheTypeMetadata type : types)
+                metas.add(from(type));
+
+        return metas;
+    }
+
+    /**
+     * @param q Actual cache query entities.
+     * @return Data transfer object for given cache type metadata.
+     */
+    public static VisorCacheTypeMetadata from(QueryEntity q) {
+        assert q != null;
+
+        VisorCacheTypeMetadata metadata = new VisorCacheTypeMetadata();
+
+        metadata.keyType = q.getKeyType();
+        metadata.valType = q.getValueType();
+
+        metadata.dbSchema = "";
+        metadata.dbTbl = "";
+
+        metadata.keyFields = Collections.emptyList();
+        metadata.valFields = Collections.emptyList();
+
+        LinkedHashMap<String, String> qryFields = q.getFields();
+
+        metadata.qryFlds = new LinkedHashMap<>(qryFields);
+
+        metadata.ascFlds = Collections.emptyMap();
+        metadata.descFlds = Collections.emptyMap();
+        metadata.txtFlds = Collections.emptyList();
+
+        Collection<QueryIndex> qryIdxs = q.getIndexes();
+
+        metadata.grps = new LinkedHashMap<>(qryIdxs.size());
+
+        for (QueryIndex qryIdx : qryIdxs) {
+            LinkedHashMap<String, Boolean> qryIdxFlds = qryIdx.getFields();
+
+            LinkedHashMap<String, IgniteBiTuple<String, Boolean>> grpFlds = new LinkedHashMap<>();
+
+            for (Map.Entry<String, Boolean> qryIdxFld : qryIdxFlds.entrySet()) {
+                String fldName = qryIdxFld.getKey();
+
+                grpFlds.put(fldName, new IgniteBiTuple<>(qryFields.get(fldName), !qryIdxFld.getValue()));
+            }
+
+            metadata.grps.put(qryIdx.getName(), grpFlds);
+        }
+
+        return metadata;
     }
 
     /**
@@ -246,4 +363,4 @@
     public Map<String, LinkedHashMap<String, IgniteBiTuple<String, Boolean>>> grps() {
         return grps;
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetBinaryTypeConfiguration.java b/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetBinaryTypeConfiguration.java
index df28aef..cae5760 100644
--- a/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetBinaryTypeConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/platform/dotnet/PlatformDotNetBinaryTypeConfiguration.java
@@ -42,6 +42,9 @@
     /** Whether to cache deserialized value. */
     private Boolean keepDeserialized;
 
+    /** Enum flag. */
+    private boolean isEnum;
+
     /**
      * Default constructor.
      */
@@ -60,6 +63,7 @@
         serializer = cfg.getSerializer();
         affinityKeyFieldName = cfg.getAffinityKeyFieldName();
         keepDeserialized = cfg.isKeepDeserialized();
+        isEnum = cfg.isEnum();
     }
 
     /**
@@ -164,6 +168,25 @@
         this.keepDeserialized = keepDeserialized;
     }
 
+    /**
+     * Gets whether this is enum type.
+     *
+     * @return {@code True} if enum.
+     */
+    public boolean isEnum() {
+        return isEnum;
+    }
+
+    /**
+     * Sets whether this is enum type.
+     *
+     * @param isEnum {@code True} if enum.
+     */
+    public void setEnum(boolean isEnum) {
+        this.isEnum = isEnum;
+    }
+
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(PlatformDotNetBinaryTypeConfiguration.class, this);
diff --git a/modules/core/src/main/java/org/apache/ignite/resources/MBeanServerResource.java b/modules/core/src/main/java/org/apache/ignite/resources/MBeanServerResource.java
deleted file mode 100644
index 17b9aa7..0000000
--- a/modules/core/src/main/java/org/apache/ignite/resources/MBeanServerResource.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.resources;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.management.MBeanServer;
-
-/**
- * Annotates a field or a setter method for injection of {@link MBeanServer} resource. MBean server
- * is provided to grid via {@link org.apache.ignite.configuration.IgniteConfiguration}.
- * <p>
- * MBean server can be injected into instances of following classes:
- * <ul>
- * <li>{@link org.apache.ignite.compute.ComputeTask}</li>
- * <li>{@link org.apache.ignite.compute.ComputeJob}</li>
- * <li>{@link org.apache.ignite.spi.IgniteSpi}</li>
- * <li>{@link org.apache.ignite.lifecycle.LifecycleBean}</li>
- * </ul>
- * <p>
- * Here is how injection would typically happen:
- * <pre name="code" class="java">
- * public class MyGridJob implements ComputeJob {
- *      ...
- *      &#64;IgniteMBeanServerResource
- *      private MBeanServer mbeanSrv;
- *      ...
- *  }
- * </pre>
- * or
- * <pre name="code" class="java">
- * public class MyGridJob implements ComputeJob {
- *     ...
- *     private MBeanSever mbeanSrv;
- *     ...
- *     &#64;IgniteMBeanServerResource
- *     public void setMBeanServer(MBeanServer mbeanSrv) {
- *          this.mbeanSrv = mbeanSrv;
- *     }
- *     ...
- * }
- * </pre>
- * <p>
- * See {@link org.apache.ignite.configuration.IgniteConfiguration#getMBeanServer()} for Grid configuration details.
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD, ElementType.FIELD})
-public @interface MBeanServerResource {
-    // No-op.
-}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/checkpoint/sharedfs/SharedFsCheckpointSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/checkpoint/sharedfs/SharedFsCheckpointSpi.java
index eb2b5a9..3a25455 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/checkpoint/sharedfs/SharedFsCheckpointSpi.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/checkpoint/sharedfs/SharedFsCheckpointSpi.java
@@ -28,12 +28,14 @@
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.resources.LoggerResource;
 import org.apache.ignite.spi.IgniteSpiAdapter;
@@ -165,6 +167,9 @@
     /** Listener. */
     private CheckpointListener lsnr;
 
+    /** Marshaller. */
+    private Marshaller marsh;
+
     /**
      * Initializes default directory paths.
      */
@@ -209,6 +214,9 @@
 
         this.gridName = gridName;
 
+        marsh = ignite.configuration().getMarshaller() instanceof BinaryMarshaller ? new JdkMarshaller() :
+            ignite.configuration().getMarshaller();
+
         folder = getNextSharedPath();
 
         if (folder == null)
@@ -307,8 +315,6 @@
         if (folder != null) {
             Map<File, SharedFsTimeData> files = new HashMap<>();
 
-            Marshaller marsh = ignite.configuration().getMarshaller();
-
             // Track expiration for only those files that are made by this node
             // to avoid file access conflicts.
             for (File file : getFiles()) {
@@ -380,7 +386,7 @@
 
         if (file.exists())
             try {
-                SharedFsCheckpointData data = SharedFsUtils.read(file, ignite.configuration().getMarshaller(), log);
+                SharedFsCheckpointData data = SharedFsUtils.read(file, marsh, log);
 
                 return data != null ?
                     data.getExpireTime() == 0 || data.getExpireTime() > U.currentTimeMillis() ?
@@ -428,7 +434,7 @@
 
             try {
                 SharedFsUtils.write(file, new SharedFsCheckpointData(state, expireTime, host, key),
-                    ignite.configuration().getMarshaller(), log);
+                    marsh, log);
             }
             catch (IOException e) {
                 // Select next shared directory if exists, otherwise throw exception
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java
index 68e2f43..b2f0f65 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java
@@ -838,6 +838,9 @@
     /** Context initialization latch. */
     private final CountDownLatch ctxInitLatch = new CountDownLatch(1);
 
+    /** Stopping flag (set to {@code true} when SPI gets stopping signal). */
+    private volatile boolean stopping;
+
     /** metrics listener. */
     private final GridNioMetricsListener metricsLsnr = new GridNioMetricsListener() {
         @Override public void onBytesSent(int bytesCnt) {
@@ -1794,6 +1797,8 @@
 
     /** {@inheritDoc} */
     @Override protected void onContextDestroyed0() {
+        stopping = true;
+
         if (ctxInitLatch.getCount() > 0)
             // Safety.
             ctxInitLatch.countDown();
@@ -1976,7 +1981,7 @@
             GridCommunicationClient client = clients.get(nodeId);
 
             if (client == null) {
-                if (isNodeStopping())
+                if (stopping)
                     throw new IgniteSpiException("Node is stopping.");
 
                 // Do not allow concurrent connects.
@@ -2311,8 +2316,8 @@
 
                         U.closeQuiet(ch);
 
-                        throw new ClusterTopologyCheckedException("Failed to send message, " +
-                            "node left cluster: " + node);
+                        throw new ClusterTopologyCheckedException("Failed to send message " +
+                            "(node left topology): " + node);
                     }
 
                     long rcvCnt = -1;
@@ -2784,18 +2789,18 @@
      * @return Node ID message.
      */
     private NodeIdMessage nodeIdMessage() {
-        ClusterNode localNode = getLocalNode();
+        ClusterNode locNode = getLocalNode();
 
         UUID id;
 
-        if (localNode == null) {
+        if (locNode == null) {
             U.warn(log, "Local node is not started or fully initialized [isStopping=" +
                     getSpiContext().isStopping() + ']');
 
             id = new UUID(0, 0);
         }
         else
-            id = localNode.id();
+            id = locNode.id();
 
         return new NodeIdMessage(id);
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
index 2c85b87..865f73f 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
@@ -4070,7 +4070,7 @@
             }
 
             if (node != null) {
-                assert !node.isLocal() : msg;
+                assert !node.isLocal() || !msg.verified() : msg;
 
                 synchronized (mux) {
                     failedNodes.add(node);
diff --git a/modules/core/src/main/resources/META-INF/classnames-jdk.properties b/modules/core/src/main/resources/META-INF/classnames-jdk.properties
index 4dd20b7..bc74998 100644
--- a/modules/core/src/main/resources/META-INF/classnames-jdk.properties
+++ b/modules/core/src/main/resources/META-INF/classnames-jdk.properties
@@ -141,6 +141,8 @@
 java.lang.reflect.Proxy
 java.lang.reflect.ReflectPermission
 java.lang.reflect.UndeclaredThrowableException
+java.math.BigDecimal
+java.math.BigInteger
 java.net.Authenticator$RequestorType
 java.net.BindException
 java.net.ConnectException
diff --git a/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStorePortableMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreBinaryMarshallerSelfTest.java
similarity index 93%
rename from modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStorePortableMarshallerSelfTest.java
rename to modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreBinaryMarshallerSelfTest.java
index 39504b1..659efb02 100644
--- a/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStorePortableMarshallerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cache/store/jdbc/CacheJdbcPojoStoreBinaryMarshallerSelfTest.java
@@ -18,12 +18,12 @@
 package org.apache.ignite.cache.store.jdbc;
 
 import org.apache.ignite.marshaller.Marshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  * Class for {@code PojoCacheStore} tests.
  */
-public class CacheJdbcPojoStorePortableMarshallerSelfTest extends CacheJdbcPojoStoreAbstractSelfTest {
+public class CacheJdbcPojoStoreBinaryMarshallerSelfTest extends CacheJdbcPojoStoreAbstractSelfTest {
     /** {@inheritDoc} */
     @Override protected Marshaller marshaller(){
         return new BinaryMarshaller();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleJobsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleJobsSelfTest.java
index d5f6287..a975e2c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleJobsSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleJobsSelfTest.java
@@ -32,6 +32,7 @@
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.lang.IgniteCallable;
 import org.apache.ignite.lang.IgniteFuture;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
@@ -97,6 +98,12 @@
             c.setCacheConfiguration(cc);
         }
 
+        TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
+
+        commSpi.setSharedMemoryPort(-1);
+
+        c.setCommunicationSpi(commSpi);
+
         return c;
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridProjectionLocalJobMultipleArgumentsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridProjectionLocalJobMultipleArgumentsSelfTest.java
index 58ff1fb..356e002 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridProjectionLocalJobMultipleArgumentsSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridProjectionLocalJobMultipleArgumentsSelfTest.java
@@ -43,7 +43,7 @@
     private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
 
     /** */
-    private static Collection<Integer> ids;
+    private static Collection<Object> ids;
 
     /** */
     private static AtomicInteger res;
@@ -90,7 +90,7 @@
         for (int i : F.asList(1, 2, 3)) {
             res.add(grid().compute().affinityCall(null, i, new IgniteCallable<Integer>() {
                 @Override public Integer call() {
-                    ids.add(System.identityHashCode(this));
+                    ids.add(this);
 
                     return 10;
                 }
@@ -108,7 +108,7 @@
         for (int i : F.asList(1, 2, 3)) {
             grid().compute().affinityRun(null, i, new IgniteRunnable() {
                 @Override public void run() {
-                    ids.add(System.identityHashCode(this));
+                    ids.add(this);
 
                     res.addAndGet(10);
                 }
@@ -125,8 +125,7 @@
     public void testCall() throws Exception {
         Collection<Integer> res = grid().compute().apply(new C1<Integer, Integer>() {
             @Override public Integer apply(Integer arg) {
-
-                ids.add(System.identityHashCode(this));
+                ids.add(this);
 
                 return 10 + arg;
             }
@@ -144,7 +143,7 @@
 
         Collection<Integer> res = grid().compute().apply(new C1<Integer, Integer>() {
             @Override public Integer apply(Integer arg) {
-                ids.add(System.identityHashCode(this));
+                ids.add(this);
 
                 return 10 + arg;
             }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectCacheTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectCacheTest.java
index 6cf10f4..14a770a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectCacheTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientReconnectCacheTest.java
@@ -56,6 +56,7 @@
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearSingleGetResponse;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxFinishResponse;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxPrepareResponse;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.CI1;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.T2;
@@ -722,15 +723,18 @@
 
         TestTcpDiscoverySpi srvSpi = spi(srv);
 
-        assertTrue(joinLatch.await(5000, MILLISECONDS));
+        try {
+            assertTrue(joinLatch.await(5000, MILLISECONDS));
 
-        U.sleep(1000);
+            U.sleep(1000);
 
-        assertNotDone(fut);
+            assertNotDone(fut);
 
-        srvSpi.failNode(clientId, null);
-
-        srvCommSpi.stopBlock(false);
+            srvSpi.failNode(clientId, null);
+        }
+        finally {
+            srvCommSpi.stopBlock(false);
+        }
 
         assertTrue(fut.get());
     }
@@ -1285,13 +1289,22 @@
 
         srvSpi.failNode(client.localNode().id(), null);
 
-        fut.get();
-
-        for (int i = 0; i < SRV_CNT; i++)
-            ((TestCommunicationSpi)grid(i).configuration().getCommunicationSpi()).stopBlock(false);
+        try {
+            fut.get();
+        }
+        finally {
+            for (int i = 0; i < SRV_CNT; i++)
+                ((TestCommunicationSpi)grid(i).configuration().getCommunicationSpi()).stopBlock(false);
+        }
 
         cache.put(1, 1);
 
+        GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                return cache.get(1) != null;
+            }
+        }, 5000);
+
         assertEquals(1, cache.get(1));
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryEnumsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryEnumsSelfTest.java
new file mode 100644
index 0000000..3bc3922
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryEnumsSelfTest.java
@@ -0,0 +1,446 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryTypeConfiguration;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.BinaryConfiguration;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * Contains tests for binary enums.
+ */
+@SuppressWarnings("unchecked")
+public class BinaryEnumsSelfTest extends GridCommonAbstractTest {
+    /** Cache name. */
+    private static String CACHE_NAME = "cache";
+
+    /** Whether to register types or not. */
+    private boolean register;
+
+    /** Node 1. */
+    private Ignite node1;
+
+    /** Node 2. */
+    private Ignite node2;
+
+    /** Cache 1. */
+    private IgniteCache cache1;
+
+    /** Cache 2. */
+    private IgniteCache cache2;
+
+    /** Binary cache 1. */
+    private IgniteCache cacheBinary1;
+
+    /** Binary cache 2. */
+    private IgniteCache cacheBinary2;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        register = false;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        if (register) {
+            BinaryConfiguration bCfg = new BinaryConfiguration();
+
+            BinaryTypeConfiguration enumCfg = new BinaryTypeConfiguration(EnumType.class.getName());
+            enumCfg.setEnum(true);
+
+            bCfg.setTypeConfigurations(Arrays.asList(enumCfg, new BinaryTypeConfiguration(EnumHolder.class.getName())));
+
+            cfg.setBinaryConfiguration(bCfg);
+        }
+
+        cfg.setMarshaller(new BinaryMarshaller());
+
+        CacheConfiguration ccfg = new CacheConfiguration();
+        ccfg.setName(CACHE_NAME);
+        ccfg.setCacheMode(CacheMode.PARTITIONED);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        return cfg;
+    }
+
+    /**
+     * Start up routine.
+     *
+     * @throws Exception If failed.
+     */
+    private void startUp(boolean register) throws Exception {
+        this.register = register;
+
+        node1 = startGrid(0);
+        cache1 = node1.cache(CACHE_NAME);
+        cacheBinary1 = cache1.withKeepBinary();
+
+        node2 = startGrid(1);
+        cache2 = node2.cache(CACHE_NAME);
+        cacheBinary2 = cache2.withKeepBinary();
+    }
+
+    /**
+     * Test operations on simple type which is registered in advance.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleRegistered() throws Exception {
+        checkSimple(true);
+    }
+
+    /**
+     * Test operations on simple type which is not registered in advance.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleNotRegistered() throws Exception {
+        checkSimple(false);
+    }
+
+    /**
+     * Test operations when enum is nested into an object (registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testNestedRegistered() throws Exception {
+        checkNested(true);
+    }
+
+    /**
+     * Test operations when enum is nested into an object (not registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testNestedNotRegistered() throws Exception {
+        checkNested(false);
+    }
+
+    /**
+     * Test builder operations on simple type which is registered in advance.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleBuilderRegistered() throws Exception {
+        checkSimpleBuilder(true);
+    }
+
+    /**
+     * Test builder operations on simple type which is not registered in advance.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleBuilderNotRegistered() throws Exception {
+        checkSimpleBuilder(false);
+    }
+
+    /**
+     * Test builder operations when enum is nested into an object (registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testNestedBuilderRegistered() throws Exception {
+        checkNestedBuilder(true);
+    }
+
+    /**
+     * Test builder operations when enum is nested into an object (not registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testNestedBuilderNotRegistered() throws Exception {
+        checkNestedBuilder(false);
+    }
+
+    /**
+     * Check simple serialization - deserialization.
+     *
+     * @param registered If type should be registered in advance.
+     * @throws Exception If failed.
+     */
+    public void checkSimple(boolean registered) throws Exception {
+        startUp(registered);
+
+        cache1.put(1, EnumType.ONE);
+
+        validateSimple(1, EnumType.ONE, registered);
+    }
+
+    /**
+     * Check nested serialization - deserialization.
+     *
+     * @param registered If type should be registered in advance.
+     * @throws Exception If failed.
+     */
+    private void checkNested(boolean registered) throws Exception {
+        startUp(registered);
+
+        cache1.put(1, new EnumHolder(EnumType.ONE));
+
+        validateNested(1, EnumType.ONE, registered);
+    }
+
+    /**
+     * Check nested builder serialization - deserialization.
+     *
+     * @param registered If type should be registered in advance.
+     * @throws Exception If failed.
+     */
+    private void checkNestedBuilder(boolean registered) throws Exception {
+        startUp(registered);
+
+        BinaryObject obj = node1.binary().builder("EnumHolder").setField("val", EnumType.ONE).build();
+
+        assert node1.binary().type("EnumHolder") != null;
+        assert node1.binary().type("EnumType") != null;
+
+        cacheBinary1.put(1, obj);
+
+        validateNested(1, EnumType.ONE, registered);
+
+        obj = (BinaryObject)cacheBinary1.get(1);
+        obj = node1.binary().builder(obj).setField("val", EnumType.TWO).build();
+
+        cacheBinary1.put(1, obj);
+
+        validateNested(1, EnumType.TWO, registered);
+    }
+
+    /**
+     * Validate nested object.
+     *
+     * @param key Key.
+     * @param val Value.
+     * @param registered Registered flag.
+     * @throws Exception If failed.
+     */
+    private void validateNested(int key, EnumType val, boolean registered) throws Exception {
+        if (registered) {
+            EnumHolder res1 = (EnumHolder) cache1.get(key);
+            EnumHolder res2 = (EnumHolder) cache2.get(key);
+
+            assertEquals(val, res1.val);
+            assertEquals(val, res2.val);
+        }
+
+        BinaryObject resBinary1 = (BinaryObject)cacheBinary1.get(key);
+        BinaryObject resBinary2 = (BinaryObject)cacheBinary2.get(key);
+
+        validate((BinaryObject)resBinary1.field("val"), val);
+        validate((BinaryObject)resBinary2.field("val"), val);
+    }
+
+    /**
+     * Check simple serialization - deserialization using builder.
+     *
+     * @param registered If type should be registered in advance.
+     * @throws Exception If failed.
+     */
+    public void checkSimpleBuilder(boolean registered) throws Exception {
+        startUp(registered);
+
+        BinaryObject binary = node1.binary().buildEnum(EnumType.class.getSimpleName(), EnumType.ONE.ordinal());
+
+        cacheBinary1.put(1, binary);
+
+        validateSimple(1, EnumType.ONE, registered);
+    }
+
+    /**
+     * Test enum array (registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleArrayRegistered() throws Exception {
+        checkSimpleArray(true);
+    }
+
+    /**
+     * Test enum array (not registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleArrayNotRegistered() throws Exception {
+        checkSimpleArray(false);
+    }
+
+    /**
+     * Test enum array created using builder (registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleBuilderArrayRegistered() throws Exception {
+        checkSimpleBuilderArray(true);
+    }
+
+    /**
+     * Test enum array created using builder (not registered).
+     *
+     * @throws Exception If failed.
+     */
+    public void testSimpleBuilderArrayNotRegistered() throws Exception {
+        checkSimpleBuilderArray(false);
+    }
+
+    /**
+     * Check arrays with builder.
+     *
+     * @param registered Registered flag.
+     * @throws Exception If failed.
+     */
+    public void checkSimpleArray(boolean registered) throws Exception {
+        startUp(registered);
+
+        cache1.put(1, new EnumType[] { EnumType.ONE, EnumType.TWO });
+
+        validateSimpleArray(registered);
+    }
+
+    /**
+     * Check arrays with builder.
+     *
+     * @param registered Registered flag.
+     * @throws Exception If failed.
+     */
+    public void checkSimpleBuilderArray(boolean registered) throws Exception {
+        startUp(registered);
+
+        BinaryObject binaryOne = node1.binary().buildEnum(EnumType.class.getSimpleName(), EnumType.ONE.ordinal());
+        BinaryObject binaryTwo = node1.binary().buildEnum(EnumType.class.getSimpleName(), EnumType.TWO.ordinal());
+
+        cacheBinary1.put(1, new BinaryObject[] { binaryOne, binaryTwo });
+
+        validateSimpleArray(registered);
+    }
+
+    /**
+     * Validate simple array.
+     *
+     * @param registered Registered flag.
+     */
+    private void validateSimpleArray(boolean registered) {
+        if (registered) {
+            Object[] arr1 = (Object[])cache1.get(1);
+            Object[] arr2 = (Object[])cache2.get(1);
+
+            assertEquals(2, arr1.length);
+            assertEquals(2, arr2.length);
+
+            assertEquals(EnumType.ONE, arr1[0]);
+            assertEquals(EnumType.TWO, arr1[1]);
+
+            assertEquals(EnumType.ONE, arr2[0]);
+            assertEquals(EnumType.TWO, arr2[1]);
+        }
+
+        Object[] arrBinary1 = (Object[])cacheBinary1.get(1);
+        Object[] arrBinary2 = (Object[])cacheBinary2.get(1);
+
+        assertEquals(2, arrBinary1.length);
+        assertEquals(2, arrBinary2.length);
+
+        validate((BinaryObject) arrBinary1[0], EnumType.ONE);
+        validate((BinaryObject) arrBinary1[1], EnumType.TWO);
+
+        validate((BinaryObject) arrBinary2[0], EnumType.ONE);
+        validate((BinaryObject) arrBinary2[1], EnumType.TWO);
+    }
+
+    /**
+     * Internal check routine for simple scenario.
+     *
+     * @param key Key.
+     * @param val Value.
+     * @param registered Registered flag.
+     * @throws Exception If failed.
+     */
+    private void validateSimple(int key, EnumType val, boolean registered) throws Exception {
+        if (registered) {
+            assertEquals(val, cache1.get(key));
+            assertEquals(val, cache2.get(key));
+        }
+
+        validate((BinaryObject) cacheBinary1.get(key), val);
+        validate((BinaryObject) cacheBinary2.get(key), val);
+    }
+
+    /**
+     * Validate single value.
+     *
+     * @param obj Binary value.
+     * @param val Expected value.
+     */
+    private void validate(BinaryObject obj, EnumType val) {
+        assertTrue(obj.type().isEnum());
+
+        assertEquals(node1.binary().typeId(EnumType.class.getName()), obj.type().typeId());
+        assertEquals(node2.binary().typeId(EnumType.class.getName()), obj.type().typeId());
+
+        assertEquals(val.ordinal(), obj.enumOrdinal());
+    }
+
+    /**
+     * Enumeration holder.
+     */
+    public static class EnumHolder implements Serializable {
+        /** Value. */
+        public EnumType val;
+
+        /**
+         * Default constructor.
+         */
+        @SuppressWarnings("UnusedDeclaration")
+        public EnumHolder() {
+            // No-op.
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param val Value.
+         */
+        public EnumHolder(EnumType val) {
+            this.val = val;
+        }
+    }
+
+    /**
+     * Enumeration for tests.
+     */
+    public static enum EnumType {
+        ONE,
+        TWO
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsAbstractSelfTest.java
index dd08390..47f3886 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsAbstractSelfTest.java
@@ -25,7 +25,6 @@
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import java.math.BigDecimal;
@@ -487,7 +486,7 @@
     private TestContext context(BinaryMarshaller marsh, String fieldName) throws Exception {
         TestObject obj = createObject();
 
-        BinaryObjectEx portObj = toPortable(marsh, obj);
+        BinaryObjectExImpl portObj = toPortable(marsh, obj);
 
         BinaryField field = portObj.type().field(fieldName);
 
@@ -507,8 +506,8 @@
         TestObject obj = createObject();
         TestOuterObject outObj = new TestOuterObject(obj);
 
-        BinaryObjectEx portOutObj = toPortable(marsh, outObj);
-        BinaryObjectEx portObj = portOutObj.field("fInner");
+        BinaryObjectExImpl portOutObj = toPortable(marsh, outObj);
+        BinaryObjectExImpl portObj = portOutObj.field("fInner");
 
         assert portObj != null;
 
@@ -534,7 +533,7 @@
      * @return Portable object.
      * @throws Exception If failed.
      */
-    protected abstract BinaryObjectEx toPortable(BinaryMarshaller marsh, Object obj) throws Exception;
+    protected abstract BinaryObjectExImpl toPortable(BinaryMarshaller marsh, Object obj) throws Exception;
 
     /**
      * Outer test object.
@@ -698,7 +697,7 @@
         public final TestObject obj;
 
         /** Portable object. */
-        public final BinaryObjectEx portObj;
+        public final BinaryObjectExImpl portObj;
 
         /** Field. */
         public final BinaryField field;
@@ -710,7 +709,7 @@
          * @param portObj Portable object.
          * @param field Field.
          */
-        public TestContext(TestObject obj, BinaryObjectEx portObj, BinaryField field) {
+        public TestContext(TestObject obj, BinaryObjectExImpl portObj, BinaryField field) {
             this.obj = obj;
             this.portObj = portObj;
             this.field = field;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsHeapSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsHeapSelfTest.java
index 53ba212..a45809f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsHeapSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsHeapSelfTest.java
@@ -17,14 +17,12 @@
 
 package org.apache.ignite.internal.portable;
 
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
-
 /**
  * Field tests for heap-based portables.
  */
 public class BinaryFieldsHeapSelfTest extends BinaryFieldsAbstractSelfTest {
     /** {@inheritDoc} */
-    @Override protected BinaryObjectEx toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
+    @Override protected BinaryObjectExImpl toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
         byte[] bytes = marsh.marshal(obj);
 
         return new BinaryObjectImpl(portableContext(marsh), bytes, 0);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsOffheapSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsOffheapSelfTest.java
index 68bfb30..2f579e1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsOffheapSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFieldsOffheapSelfTest.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.portable;
 
 import org.apache.ignite.internal.util.GridUnsafe;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.eclipse.jetty.util.ConcurrentHashSet;
 import sun.misc.Unsafe;
 
@@ -47,7 +46,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected BinaryObjectEx toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
+    @Override protected BinaryObjectExImpl toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
         byte[] arr = marsh.marshal(obj);
 
         long ptr = UNSAFE.allocateMemory(arr.length);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsAbstractSelfTest.java
index 7267b16..38c0137 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsAbstractSelfTest.java
@@ -24,7 +24,6 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 /**
@@ -128,7 +127,7 @@
     private void check(int len) throws Exception {
         TestObject obj = new TestObject(len);
 
-        BinaryObjectEx portObj = toPortable(marsh, obj);
+        BinaryObjectExImpl portObj = toPortable(marsh, obj);
 
         // 1. Test portable object content.
         assert portObj.hasField("field1");
@@ -170,7 +169,7 @@
      * @return Portable object.
      * @throws Exception If failed.
      */
-    protected abstract BinaryObjectEx toPortable(BinaryMarshaller marsh, Object obj) throws Exception;
+    protected abstract BinaryObjectExImpl toPortable(BinaryMarshaller marsh, Object obj) throws Exception;
 
     /**
      * Test object.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsHeapSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsHeapSelfTest.java
index 471bd44..bc48bef 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsHeapSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsHeapSelfTest.java
@@ -17,14 +17,12 @@
 
 package org.apache.ignite.internal.portable;
 
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
-
 /**
  * Compact offsets tests for heap portable objects.
  */
 public class BinaryFooterOffsetsHeapSelfTest extends BinaryFooterOffsetsAbstractSelfTest {
     /** {@inheritDoc} */
-    @Override protected BinaryObjectEx toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
+    @Override protected BinaryObjectExImpl toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
         byte[] bytes = marsh.marshal(obj);
 
         return new BinaryObjectImpl(ctx, bytes, 0);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsOffheapSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsOffheapSelfTest.java
index 7b44b80..a2c0a05 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsOffheapSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryFooterOffsetsOffheapSelfTest.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal.portable;
 
 import org.apache.ignite.internal.util.GridUnsafe;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.eclipse.jetty.util.ConcurrentHashSet;
 import sun.misc.Unsafe;
 
@@ -47,7 +46,7 @@
     }
 
     /** {@inheritDoc} */
-    @Override protected BinaryObjectEx toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
+    @Override protected BinaryObjectExImpl toPortable(BinaryMarshaller marsh, Object obj) throws Exception {
         byte[] arr = marsh.marshal(obj);
 
         long ptr = UNSAFE.allocateMemory(arr.length);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
index 19c40b3..cc035f6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryMarshallerSelfTest.java
@@ -17,6 +17,10 @@
 
 package org.apache.ignite.internal.portable;
 
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
 import junit.framework.Assert;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.binary.BinaryIdMapper;
@@ -41,7 +45,6 @@
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.jsr166.ConcurrentHashMap8;
@@ -365,6 +368,23 @@
     /**
      * @throws Exception If failed.
      */
+    public void testExternalizableHashCode() throws Exception {
+        SimpleExternalizable sim1 = new SimpleExternalizable("Simple");
+        SimpleExternalizable sim2 = new SimpleExternalizable("Simple");
+
+        BinaryMarshaller marsh = binaryMarshaller();
+
+        BinaryObjectImpl sim1Binary = marshal(sim1, marsh);
+        BinaryObjectImpl sim2Binary = marshal(sim2, marsh);
+
+        assertEquals(sim1.hashCode(), sim2.hashCode());
+        assertEquals(sim1.hashCode(), sim1Binary.hashCode());
+        assertEquals(sim2.hashCode(), sim2Binary.hashCode());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testMapEntry() throws Exception {
         Map.Entry<Integer, String> e = new GridMapEntry<>(1, "str1");
 
@@ -488,8 +508,8 @@
         assertArrayEquals(obj.objArr, (Object[])po.field("objArr"));
         assertEquals(obj.col, po.field("col"));
         assertEquals(obj.map, po.field("map"));
-        assertEquals(new Integer(obj.enumVal.ordinal()), new Integer(((Enum<?>)po.field("enumVal")).ordinal()));
-        assertArrayEquals(ordinals(obj.enumArr), ordinals((Enum<?>[])po.field("enumArr")));
+        assertEquals(new Integer(obj.enumVal.ordinal()), new Integer(((BinaryObject)po.field("enumVal")).enumOrdinal()));
+        assertArrayEquals(ordinals(obj.enumArr), ordinals((BinaryObject[])po.field("enumArr")));
         assertNull(po.field("unknown"));
 
         BinaryObject innerPo = po.field("inner");
@@ -524,8 +544,8 @@
         assertEquals(obj.inner.col, innerPo.field("col"));
         assertEquals(obj.inner.map, innerPo.field("map"));
         assertEquals(new Integer(obj.inner.enumVal.ordinal()),
-            new Integer(((Enum<?>)innerPo.field("enumVal")).ordinal()));
-        assertArrayEquals(ordinals(obj.inner.enumArr), ordinals((Enum<?>[])innerPo.field("enumArr")));
+            new Integer(((BinaryObject)innerPo.field("enumVal")).enumOrdinal()));
+        assertArrayEquals(ordinals(obj.inner.enumArr), ordinals((BinaryObject[])innerPo.field("enumArr")));
         assertNull(innerPo.field("inner"));
         assertNull(innerPo.field("unknown"));
     }
@@ -573,8 +593,8 @@
         assertArrayEquals(obj.objArr, (Object[])po.field("_objArr"));
         assertEquals(obj.col, po.field("_col"));
         assertEquals(obj.map, po.field("_map"));
-        assertEquals(new Integer(obj.enumVal.ordinal()), new Integer(((Enum<?>)po.field("_enumVal")).ordinal()));
-        assertArrayEquals(ordinals(obj.enumArr), ordinals((Enum<?>[])po.field("_enumArr")));
+        assertEquals(new Integer(obj.enumVal.ordinal()), new Integer(((BinaryObject)po.field("_enumVal")).enumOrdinal()));
+        assertArrayEquals(ordinals(obj.enumArr), ordinals((BinaryObject[])po.field("_enumArr")));
         assertNull(po.field("unknown"));
 
         BinaryObject simplePo = po.field("_simple");
@@ -609,8 +629,8 @@
         assertEquals(obj.simple.col, simplePo.field("col"));
         assertEquals(obj.simple.map, simplePo.field("map"));
         assertEquals(new Integer(obj.simple.enumVal.ordinal()),
-            new Integer(((Enum<?>)simplePo.field("enumVal")).ordinal()));
-        assertArrayEquals(ordinals(obj.simple.enumArr), ordinals((Enum<?>[])simplePo.field("enumArr")));
+            new Integer(((BinaryObject)simplePo.field("enumVal")).enumOrdinal()));
+        assertArrayEquals(ordinals(obj.simple.enumArr), ordinals((BinaryObject[])simplePo.field("enumArr")));
         assertNull(simplePo.field("simple"));
         assertNull(simplePo.field("portable"));
         assertNull(simplePo.field("unknown"));
@@ -646,8 +666,8 @@
         assertEquals(obj.portable.col, portablePo.field("_col"));
         assertEquals(obj.portable.map, portablePo.field("_map"));
         assertEquals(new Integer(obj.portable.enumVal.ordinal()),
-            new Integer(((Enum<?>)portablePo.field("_enumVal")).ordinal()));
-        assertArrayEquals(ordinals(obj.portable.enumArr), ordinals((Enum<?>[])portablePo.field("_enumArr")));
+            new Integer(((BinaryObject)portablePo.field("_enumVal")).enumOrdinal()));
+        assertArrayEquals(ordinals(obj.portable.enumArr), ordinals((BinaryObject[])portablePo.field("_enumArr")));
         assertNull(portablePo.field("_simple"));
         assertNull(portablePo.field("_portable"));
         assertNull(portablePo.field("unknown"));
@@ -685,8 +705,8 @@
         assertArrayEquals(obj.objArr, (Object[])po.field("objArr"));
         assertEquals(obj.col, po.field("col"));
         assertEquals(obj.map, po.field("map"));
-        assertEquals(new Integer(obj.enumVal.ordinal()), new Integer(((Enum<?>)po.field("enumVal")).ordinal()));
-        assertArrayEquals(ordinals(obj.enumArr), ordinals((Enum<?>[])po.field("enumArr")));
+        assertEquals(new Integer(obj.enumVal.ordinal()), new Integer(((BinaryObject)po.field("enumVal")).enumOrdinal()));
+        assertArrayEquals(ordinals(obj.enumArr), ordinals((BinaryObject[])po.field("enumArr")));
         assertNull(po.field("unknown"));
 
         assertEquals(obj, po.deserialize());
@@ -792,9 +812,9 @@
 
         CustomMappedObject1 obj1 = new CustomMappedObject1(10, "str");
 
-        BinaryObjectEx po1 = marshal(obj1, marsh);
+        BinaryObjectExImpl po1 = marshal(obj1, marsh);
 
-        assertEquals(11111, po1.typeId());
+        assertEquals(11111, po1.type().typeId());
         assertEquals((Integer)10, po1.field(22222));
         assertEquals("str", po1.field(33333));
 
@@ -849,9 +869,9 @@
 
         CustomMappedObject1 obj1 = new CustomMappedObject1(10, "str1");
 
-        BinaryObjectEx po1 = marshal(obj1, marsh);
+        BinaryObjectExImpl po1 = marshal(obj1, marsh);
 
-        assertEquals(11111, po1.typeId());
+        assertEquals(11111, po1.type().typeId());
         assertEquals((Integer)10, po1.field(22222));
         assertEquals("str1", po1.field(33333));
 
@@ -860,9 +880,9 @@
 
         CustomMappedObject2 obj2 = new CustomMappedObject2(20, "str2");
 
-        BinaryObjectEx po2 = marshal(obj2, marsh);
+        BinaryObjectExImpl po2 = marshal(obj2, marsh);
 
-        assertEquals(44444, po2.typeId());
+        assertEquals(44444, po2.type().typeId());
         assertEquals((Integer)20, po2.field(55555));
         assertEquals("str2", po2.field(66666));
 
@@ -1774,7 +1794,7 @@
             assertTrue(offheapObj.equals(offheapObj1));
             assertTrue(offheapObj1.equals(offheapObj));
 
-            assertEquals(obj.typeId(), offheapObj.typeId());
+            assertEquals(obj.type().typeId(), offheapObj.type().typeId());
             assertEquals(obj.hashCode(), offheapObj.hashCode());
 
             checkSimpleObjectData(simpleObj, offheapObj);
@@ -1787,7 +1807,7 @@
 
             obj = (BinaryObjectImpl)offheapObj.heapCopy();
 
-            assertEquals(obj.typeId(), offheapObj.typeId());
+            assertEquals(obj.type().typeId(), offheapObj.type().typeId());
             assertEquals(obj.hashCode(), offheapObj.hashCode());
 
             checkSimpleObjectData(simpleObj, obj);
@@ -2085,7 +2105,7 @@
             if (id == GridPortableMarshaller.UNREGISTERED_TYPE_ID)
                 continue;
 
-            PortableClassDescriptor desc = pCtx.descriptorForTypeId(false, entry.getValue(), null);
+            PortableClassDescriptor desc = pCtx.descriptorForTypeId(false, entry.getValue(), null, false);
 
             assertEquals(desc.typeId(), pCtx.typeId(desc.describedClass().getName()));
             assertEquals(desc.typeId(), pCtx.typeId(pCtx.typeName(desc.describedClass().getName())));
@@ -2204,6 +2224,19 @@
     }
 
     /**
+     * @param enumArr Enum array.
+     * @return Ordinals.
+     */
+    private <T extends Enum<?>> Integer[] ordinals(BinaryObject[] enumArr) {
+        Integer[] ords = new Integer[enumArr.length];
+
+        for (int i = 0; i < enumArr.length; i++)
+            ords[i] = enumArr[i].enumOrdinal();
+
+        return ords;
+    }
+
+    /**
      * @param po Portable object.
      * @param off Offset.
      * @return Value.
@@ -3609,6 +3642,49 @@
     /**
      *
      */
+    public static class SimpleExternalizable implements Externalizable {
+        /** */
+        private String field;
+
+        /**
+         * @param field Field.
+         */
+        public SimpleExternalizable(String field) {
+            this.field = field;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeExternal(ObjectOutput out) throws IOException {
+            U.writeString(out, field);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+            field = U.readString(in);
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            SimpleExternalizable that = (SimpleExternalizable)o;
+
+            return field.equals(that.field);
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return field.hashCode();
+        }
+    }
+
+    /**
+     *
+     */
     private static class ParentPortable {
         /** */
         public String s;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java
index 356a25b..cfeb714 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java
@@ -46,7 +46,6 @@
 import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.processors.cache.portable.IgniteBinaryImpl;
 import org.apache.ignite.internal.util.lang.GridMapEntry;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectBuilder;
 import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.binary.BinaryObject;
@@ -968,7 +967,7 @@
 
         mutableObj.build();
 
-        BinaryType metadata = portables().metadata(TestObjectContainer.class);
+        BinaryType metadata = portables().type(TestObjectContainer.class);
 
         assertEquals("String", metadata.fieldTypeName("xx567"));
     }
@@ -984,7 +983,7 @@
 
         mutableObj.build();
 
-        BinaryType metadata = portables().metadata(TestObjectContainer.class);
+        BinaryType metadata = portables().type(TestObjectContainer.class);
 
         assertEquals("String", metadata.fieldTypeName("xx567"));
     }
@@ -1008,7 +1007,7 @@
 
         mutableObj.build();
 
-        BinaryType metadata = portables().metadata(c.getClass());
+        BinaryType metadata = portables().type(c.getClass());
 
         assertTrue(metadata.fieldNames().containsAll(Arrays.asList("intField", "intArrField", "arrField", "strField",
             "colField", "mapField", "enumField", "enumArrField")));
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java
index 7f023f3..66bd77e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java
@@ -44,7 +44,6 @@
 import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
 import org.apache.ignite.internal.util.GridUnsafe;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import sun.misc.Unsafe;
@@ -52,6 +51,7 @@
 /**
  * Portable builder test.
  */
+@SuppressWarnings("ResultOfMethodCallIgnored")
 public class BinaryObjectBuilderSelfTest extends GridCommonAbstractTest {
     /** */
     private static final Unsafe UNSAFE = GridUnsafe.unsafe();
@@ -126,6 +126,36 @@
     /**
      * @throws Exception If failed.
      */
+    public void testNullField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(42);
+
+        builder.setField("objField", (Object)null);
+
+        builder.setField("otherField", "value");
+
+        BinaryObject obj = builder.build();
+
+        assertNull(obj.field("objField"));
+        assertEquals("value", obj.field("otherField"));
+        assertEquals(42, obj.hashCode());
+
+        builder = builder(obj);
+
+        builder.setField("objField", "value");
+        builder.setField("otherField", (Object)null);
+
+        obj = builder.build();
+
+        assertNull(obj.field("otherField"));
+        assertEquals("value", obj.field("objField"));
+        assertEquals(42, obj.hashCode());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testByteField() throws Exception {
         BinaryObjectBuilder builder = builder("Class");
 
@@ -135,7 +165,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals((byte) 1, po.<Byte>field("byteField").byteValue());
@@ -153,7 +183,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals((short)1, po.<Short>field("shortField").shortValue());
@@ -171,7 +201,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(1, po.<Integer>field("intField").intValue());
@@ -189,7 +219,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(1L, po.<Long>field("longField").longValue());
@@ -207,7 +237,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(1.0f, po.<Float>field("floatField").floatValue(), 0);
@@ -225,7 +255,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(1.0d, po.<Double>field("doubleField").doubleValue(), 0);
@@ -243,7 +273,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals((char)1, po.<Character>field("charField").charValue());
@@ -261,7 +291,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(po.<Boolean>field("booleanField"));
@@ -279,10 +309,10 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
-        assertEquals(BigDecimal.TEN, po.<String>field("decimalField"));
+        assertEquals(BigDecimal.TEN, po.<BigDecimal>field("decimalField"));
     }
 
     /**
@@ -297,7 +327,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals("str", po.<String>field("stringField"));
@@ -336,7 +366,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(uuid, po.<UUID>field("uuidField"));
@@ -354,7 +384,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new byte[] {1, 2, 3}, po.<byte[]>field("byteArrayField")));
@@ -372,7 +402,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new short[] {1, 2, 3}, po.<short[]>field("shortArrayField")));
@@ -390,7 +420,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new int[] {1, 2, 3}, po.<int[]>field("intArrayField")));
@@ -408,7 +438,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new long[] {1, 2, 3}, po.<long[]>field("longArrayField")));
@@ -426,7 +456,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new float[] {1, 2, 3}, po.<float[]>field("floatArrayField")));
@@ -444,7 +474,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new double[] {1, 2, 3}, po.<double[]>field("doubleArrayField")));
@@ -462,7 +492,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new char[] {1, 2, 3}, po.<char[]>field("charArrayField")));
@@ -480,7 +510,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         boolean[] arr = po.field("booleanArrayField");
@@ -503,7 +533,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new BigDecimal[] {BigDecimal.ONE, BigDecimal.TEN}, po.<String[]>field("decimalArrayField")));
@@ -521,7 +551,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(new String[] {"str1", "str2", "str3"}, po.<String[]>field("stringArrayField")));
@@ -568,7 +598,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertTrue(Arrays.equals(arr, po.<UUID[]>field("uuidArrayField")));
@@ -586,7 +616,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(1, po.<BinaryObject>field("objectField").<Value>deserialize().i);
@@ -604,7 +634,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         Object[] arr = po.field("objectArrayField");
@@ -627,7 +657,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         List<BinaryObject> list = po.field("collectionField");
@@ -650,7 +680,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         Map<BinaryObject, BinaryObject> map = po.field("mapField");
@@ -677,7 +707,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("class".hashCode(), po.typeId());
+        assertEquals("class".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(111, po.<Integer>field("i").intValue());
@@ -727,7 +757,7 @@
 
             assertEquals(BinaryObjectOffheapImpl.class, offheapObj.getClass());
 
-            assertEquals("class".hashCode(), offheapObj.typeId());
+            assertEquals("class".hashCode(), offheapObj.type().typeId());
             assertEquals(100, offheapObj.hashCode());
 
             assertEquals(111, offheapObj.<Integer>field("i").intValue());
@@ -762,7 +792,7 @@
 
         BinaryObject po = builder.build();
 
-        assertEquals("value".hashCode(), po.typeId());
+        assertEquals("value".hashCode(), po.type().typeId());
         assertEquals(100, po.hashCode());
 
         assertEquals(1, po.<Value>deserialize().i);
@@ -856,6 +886,7 @@
     /**
      *
      */
+    @SuppressWarnings("unchecked")
     public void testCopyFromInnerObjects() {
         ArrayList<Object> list = new ArrayList<>();
         list.add(new TestObjectAllTypes());
@@ -898,7 +929,7 @@
         assertTrue(builder.getField("plainPortable") instanceof BinaryObject);
 
         TestObjectPlainPortable deserialized = builder.build().deserialize();
-        assertTrue(deserialized.plainPortable instanceof BinaryObject);
+        assertTrue(deserialized.plainPortable != null);
     }
 
     /**
@@ -987,20 +1018,21 @@
     /**
      * @return Builder.
      */
-    private <T> BinaryObjectBuilder builder(String clsName) {
+    private BinaryObjectBuilder builder(String clsName) {
         return portables().builder(clsName);
     }
 
     /**
      * @return Builder.
      */
-    private <T> BinaryObjectBuilderImpl builder(BinaryObject obj) {
+    private BinaryObjectBuilderImpl builder(BinaryObject obj) {
         return (BinaryObjectBuilderImpl)portables().builder(obj);
     }
 
     /**
      *
      */
+    @SuppressWarnings("UnusedDeclaration")
     private static class CustomIdMapper {
         /** */
         private String str = "a";
@@ -1011,6 +1043,7 @@
 
     /**
      */
+    @SuppressWarnings("UnusedDeclaration")
     private static class Key {
         /** */
         private int i;
@@ -1049,6 +1082,7 @@
 
     /**
      */
+    @SuppressWarnings("UnusedDeclaration")
     private static class Value {
         /** */
         private int i;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableAffinityKeySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableAffinityKeySelfTest.java
index 9fb3a6f..c243901 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableAffinityKeySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableAffinityKeySelfTest.java
@@ -21,6 +21,7 @@
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.Ignite;
+import org.apache.ignite.binary.BinaryObjectBuilder;
 import org.apache.ignite.cache.CacheKeyConfiguration;
 import org.apache.ignite.cache.affinity.Affinity;
 import org.apache.ignite.configuration.BinaryConfiguration;
@@ -33,7 +34,6 @@
 import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
 import org.apache.ignite.lang.IgniteCallable;
 import org.apache.ignite.lang.IgniteRunnable;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryTypeConfiguration;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
@@ -71,8 +71,9 @@
         cfg.setBinaryConfiguration(bCfg);
 
         CacheKeyConfiguration keyCfg = new CacheKeyConfiguration(TestObject.class.getName(), "affKey");
+        CacheKeyConfiguration keyCfg2 = new CacheKeyConfiguration("TestObject2", "affKey");
 
-        cfg.setCacheKeyCfg(keyCfg);
+        cfg.setCacheKeyCfg(keyCfg, keyCfg2);
 
         cfg.setMarshaller(new BinaryMarshaller());
 
@@ -136,6 +137,14 @@
 
             assertEquals(i, aff.affinityKey(new TestObject(i)));
 
+            assertEquals(i, aff.affinityKey(ignite.binary().toBinary(new TestObject(i))));
+
+            BinaryObjectBuilder bldr = ignite.binary().builder("TestObject2");
+
+            bldr.setField("affKey", i);
+
+            assertEquals(i, aff.affinityKey(bldr.build()));
+
             CacheObject cacheObj = cacheObjProc.toCacheObject(cacheObjCtx, new TestObject(i), true);
 
             assertEquals(i, aff.affinityKey(cacheObj));
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMarshallerCtxDisabledSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMarshallerCtxDisabledSelfTest.java
index 917298a..346cf80 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMarshallerCtxDisabledSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMarshallerCtxDisabledSelfTest.java
@@ -25,7 +25,6 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.MarshallerContextAdapter;
 import org.apache.ignite.internal.util.IgniteUtils;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import java.io.Externalizable;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMetaDataSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMetaDataSelfTest.java
index 5c25d3b..f2bca9a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMetaDataSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableMetaDataSelfTest.java
@@ -26,7 +26,6 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.Binarylizable;
 import org.apache.ignite.binary.BinaryType;
@@ -87,7 +86,7 @@
     public void testGetAll() throws Exception {
         portables().toBinary(new TestObject2());
 
-        Collection<BinaryType> metas = portables().metadata();
+        Collection<BinaryType> metas = portables().types();
 
         assertEquals(2, metas.size());
 
@@ -153,14 +152,14 @@
     public void testNoConfiguration() throws Exception {
         portables().toBinary(new TestObject3());
 
-        assertNotNull(portables().metadata(TestObject3.class));
+        assertNotNull(portables().type(TestObject3.class));
     }
 
     /**
      * @throws Exception If failed.
      */
     public void testReflection() throws Exception {
-        BinaryType meta = portables().metadata(TestObject1.class);
+        BinaryType meta = portables().type(TestObject1.class);
 
         assertNotNull(meta);
 
@@ -193,7 +192,7 @@
     public void testPortableMarshalAware() throws Exception {
         portables().toBinary(new TestObject2());
 
-        BinaryType meta = portables().metadata(TestObject2.class);
+        BinaryType meta = portables().type(TestObject2.class);
 
         assertNotNull(meta);
 
@@ -230,7 +229,7 @@
 
         portables().toBinary(new TestObject2());
 
-        BinaryType meta = portables().metadata(TestObject2.class);
+        BinaryType meta = portables().type(TestObject2.class);
 
         assertNotNull(meta);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableWildcardsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableWildcardsSelfTest.java
index a00ad75..0fb5381 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableWildcardsSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/GridPortableWildcardsSelfTest.java
@@ -27,7 +27,6 @@
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 
 import java.util.Arrays;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDeferredDeleteSanitySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDeferredDeleteSanitySelfTest.java
new file mode 100644
index 0000000..5040172
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheDeferredDeleteSanitySelfTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.LOCAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+
+/**
+ * Sanity tests of deferred delete for different cache configurations.
+ */
+public class CacheDeferredDeleteSanitySelfTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrid(0);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If fails.
+     */
+    public void testDeferredDelete() throws Exception {
+        testDeferredDelete(LOCAL, ATOMIC, false, false);
+        testDeferredDelete(LOCAL, TRANSACTIONAL, false, false);
+
+        testDeferredDelete(PARTITIONED, ATOMIC, false, true);
+        testDeferredDelete(PARTITIONED, TRANSACTIONAL, false, true);
+
+        testDeferredDelete(REPLICATED, ATOMIC, false, true);
+        testDeferredDelete(REPLICATED, TRANSACTIONAL, false, true);
+
+        // Near
+        testDeferredDelete(LOCAL, ATOMIC, true, false);
+        testDeferredDelete(LOCAL, TRANSACTIONAL, true, false);
+
+        testDeferredDelete(PARTITIONED, ATOMIC, true, true);
+        testDeferredDelete(PARTITIONED, TRANSACTIONAL, true, false);
+
+        testDeferredDelete(REPLICATED, ATOMIC, true, true);
+        testDeferredDelete(REPLICATED, TRANSACTIONAL, true, true);
+    }
+
+    /**
+     * @param mode Mode.
+     * @param atomicityMode Atomicity mode.
+     * @param near Near cache enabled.
+     * @param expVal Expected deferred delete value.
+     */
+    @SuppressWarnings("unchecked")
+    private void testDeferredDelete(CacheMode mode, CacheAtomicityMode atomicityMode, boolean near, boolean expVal) {
+        CacheConfiguration ccfg = new CacheConfiguration()
+            .setCacheMode(mode)
+            .setAtomicityMode(atomicityMode);
+
+        if (near)
+            ccfg.setNearConfiguration(new NearCacheConfiguration());
+
+        IgniteCache cache = null;
+
+        try {
+            cache = grid(0).getOrCreateCache(ccfg);
+
+            assertEquals(expVal, ((IgniteCacheProxy)grid(0).cache(null)).context().deferredDelete());
+        }
+        finally {
+            if (cache != null)
+                cache.destroy();
+        }
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java
new file mode 100644
index 0000000..0e0e521
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CachePutEventListenerErrorSelfTest.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.UUID;
+import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMemoryMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.events.Event;
+import org.apache.ignite.events.EventType;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Test for cache put with error in event listener.
+ */
+public class CachePutEventListenerErrorSelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(disco);
+
+        cfg.setIncludeEventTypes(EventType.EVT_CACHE_OBJECT_PUT);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGridsMultiThreaded(3);
+
+        Ignition.setClientMode(true);
+
+        Ignite ignite = startGrid("client");
+
+        ignite.events().remoteListen(
+            new IgniteBiPredicate<UUID, Event>() {
+                @Override public boolean apply(UUID uuid, Event evt) {
+                    return true;
+                }
+            },
+            new IgnitePredicate<Event>() {
+                @Override public boolean apply(Event evt) {
+                    throw new NoClassDefFoundError("XXX");
+                }
+            },
+            EventType.EVT_CACHE_OBJECT_PUT
+        );
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPartitionedAtomicOnHeap() throws Exception {
+        doTest(CacheMode.PARTITIONED, CacheAtomicityMode.ATOMIC, CacheMemoryMode.ONHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPartitionedAtomicOffHeap() throws Exception {
+        doTest(CacheMode.PARTITIONED, CacheAtomicityMode.ATOMIC, CacheMemoryMode.OFFHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPartitionedTransactionalOnHeap() throws Exception {
+        doTest(CacheMode.PARTITIONED, CacheAtomicityMode.TRANSACTIONAL, CacheMemoryMode.ONHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPartitionedTransactionalOffHeap() throws Exception {
+        doTest(CacheMode.PARTITIONED, CacheAtomicityMode.TRANSACTIONAL, CacheMemoryMode.OFFHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testReplicatedAtomicOnHeap() throws Exception {
+        doTest(CacheMode.REPLICATED, CacheAtomicityMode.ATOMIC, CacheMemoryMode.ONHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testReplicatedAtomicOffHeap() throws Exception {
+        doTest(CacheMode.REPLICATED, CacheAtomicityMode.ATOMIC, CacheMemoryMode.OFFHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testReplicatedTransactionalOnHeap() throws Exception {
+        doTest(CacheMode.REPLICATED, CacheAtomicityMode.TRANSACTIONAL, CacheMemoryMode.ONHEAP_TIERED);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testReplicatedTransactionalOffHeap() throws Exception {
+        doTest(CacheMode.REPLICATED, CacheAtomicityMode.TRANSACTIONAL, CacheMemoryMode.OFFHEAP_TIERED);
+    }
+
+    /**
+     * @param cacheMode Cache mode.
+     * @param atomicityMode Atomicity mode.
+     * @param memMode Memory mode.
+     * @throws Exception If failed.
+     */
+    private void doTest(CacheMode cacheMode, CacheAtomicityMode atomicityMode, CacheMemoryMode memMode)
+        throws Exception {
+        Ignite ignite = grid("client");
+
+        try {
+            CacheConfiguration<Integer, Integer> cfg = defaultCacheConfiguration();
+
+            cfg.setName("cache");
+            cfg.setCacheMode(cacheMode);
+            cfg.setAtomicityMode(atomicityMode);
+            cfg.setMemoryMode(memMode);
+
+            IgniteCache<Integer, Integer> cache = ignite.createCache(cfg).withAsync();
+
+            cache.put(0, 0);
+
+            try {
+                cache.future().get(2000);
+
+                assert false : "Exception was not thrown";
+            }
+            catch (CacheException e) {
+                info("Caught expected exception: " + e);
+            }
+        }
+        finally {
+            ignite.destroyCache("cache");
+        }
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java
index 29828af..061a374 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheStopAndDestroySelfTest.java
@@ -30,6 +30,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.managers.communication.GridIoMessage;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareRequest;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteInClosure;
@@ -67,9 +68,6 @@
     /** local cache name. */
     protected static String CACHE_NAME_LOC = "cache_local";
 
-    /** */
-    private static volatile boolean stop;
-
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         super.beforeTest();
@@ -674,6 +672,10 @@
 
         // Local creation after closed.
 
+        AffinityTopologyVersion topVer = grid(1).context().cache().context().exchange().lastTopologyFuture().get();
+
+        grid(0).context().cache().context().exchange().affinityReadyFuture(topVer).get();
+
         grid(0).getOrCreateCache(getLocalConfig());
 
         grid(0).cache(CACHE_NAME_LOC).put(KEY_VAL, KEY_VAL + "recreated0");
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java
index e8e86e9..084fe83 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheAbstractFullApiSelfTest.java
@@ -17,8 +17,6 @@
 
 package org.apache.ignite.internal.processors.cache;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -38,6 +36,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Lock;
 import javax.cache.Cache;
+import javax.cache.CacheException;
 import javax.cache.expiry.Duration;
 import javax.cache.expiry.ExpiryPolicy;
 import javax.cache.expiry.TouchedExpiryPolicy;
@@ -45,6 +44,8 @@
 import javax.cache.processor.EntryProcessorException;
 import javax.cache.processor.EntryProcessorResult;
 import javax.cache.processor.MutableEntry;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 import junit.framework.AssertionFailedError;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
@@ -2392,6 +2393,60 @@
     /**
      * @throws Exception If failed.
      */
+    public void testGetAndRemoveObject() throws Exception {
+        IgniteCache<String, TestValue> cache = ignite(0).cache(null);
+
+        TestValue val1 = new TestValue(1);
+        TestValue val2 = new TestValue(2);
+
+        cache.put("key1", val1);
+        cache.put("key2", val2);
+
+        assert !cache.remove("key1", new TestValue(0));
+
+        TestValue oldVal = cache.get("key1");
+
+        assert oldVal != null && F.eq(val1, oldVal);
+
+        assert cache.remove("key1");
+
+        assert cache.get("key1") == null;
+
+        TestValue oldVal2 = cache.getAndRemove("key2");
+
+        assert F.eq(val2, oldVal2);
+
+        assert cache.get("key2") == null;
+        assert cache.getAndRemove("key2") == null;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testGetAndPutObject() throws Exception {
+        IgniteCache<String, TestValue> cache = ignite(0).cache(null);
+
+        TestValue val1 = new TestValue(1);
+        TestValue val2 = new TestValue(2);
+
+        cache.put("key1", val1);
+
+        TestValue oldVal = cache.get("key1");
+
+        assertEquals(val1, oldVal);
+
+        oldVal = cache.getAndPut("key1", val2);
+
+        assertEquals(val1, oldVal);
+
+        TestValue updVal = cache.get("key1");
+
+        assertEquals(val2, updVal);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testDeletedEntriesFlag() throws Exception {
         if (cacheMode() != LOCAL && cacheMode() != REPLICATED && memoryMode() != OFFHEAP_TIERED) {
             final int cnt = 3;
@@ -5128,6 +5183,43 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testLockInsideTransaction() throws Exception {
+        if (txEnabled()) {
+            GridTestUtils.assertThrows(
+                log,
+                new Callable<Object>() {
+                    @Override public Object call() throws Exception {
+                        try (Transaction tx = ignite(0).transactions().txStart()) {
+                            jcache(0).lock("key").lock();
+                        }
+
+                        return null;
+                    }
+                },
+                CacheException.class,
+                "Explicit lock can't be acquired within a transaction."
+            );
+
+            GridTestUtils.assertThrows(
+                log,
+                new Callable<Object>() {
+                    @Override public Object call() throws Exception {
+                        try (Transaction tx = ignite(0).transactions().txStart()) {
+                            jcache(0).lockAll(Arrays.asList("key1", "key2")).lock();
+                        }
+
+                        return null;
+                    }
+                },
+                CacheException.class,
+                "Explicit lock can't be acquired within a transaction."
+            );
+        }
+    }
+
+    /**
      * Sets given value, returns old value.
      */
     public static final class SetValueProcessor implements EntryProcessor<String, Integer, Integer> {
@@ -5440,4 +5532,47 @@
             throw new EntryProcessorException("Test entry processor exception.");
         }
     }
+
+    /**
+     *
+     */
+    private static class TestValue implements Serializable {
+        /** */
+        private int val;
+
+        /**
+         * @param val Value.
+         */
+        TestValue(int val) {
+            this.val = val;
+        }
+
+        /**
+         * @return Value.
+         */
+        public int value() {
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (!(o instanceof TestValue))
+                return false;
+
+            TestValue value = (TestValue)o;
+
+            if (val != value.val)
+                return false;
+
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return val;
+        }
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapSelfTest.java
index 3381a34..1f494c0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheConcurrentMapSelfTest.java
@@ -362,4 +362,4 @@
             assertEquals(0, local().map.iteratorMapSize());
         }
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOnCopyFlagAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOnCopyFlagAbstractSelfTest.java
index 10fb661..b9c1449 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOnCopyFlagAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOnCopyFlagAbstractSelfTest.java
@@ -284,6 +284,8 @@
 
         GridCacheContext cctx = cache0.context();
 
+        boolean binary = cctx.cacheObjects().isPortableEnabled(null);
+
         for (Map.Entry<TestKey, TestValue> e : map.entrySet()) {
             GridCacheEntryEx entry = cache0.peekEx(e.getKey());
 
@@ -295,7 +297,10 @@
 
             TestKey key1 = entry.key().value(cctx.cacheObjectContext(), true);
 
-            assertSame(key0, key1);
+            if (!binary)
+                assertSame(key0, key1);
+            else
+                assertNotSame(key0, key1);
 
             TestValue val0 = entry.rawGet().value(cctx.cacheObjectContext(), false);
 
@@ -330,6 +335,8 @@
 
         GridCacheContext cctx = cache0.context();
 
+        boolean binary = cctx.cacheObjects().isPortableEnabled(null);
+
         for (Map.Entry<TestKey, byte[]> e : map.entrySet()) {
             GridCacheEntryEx entry = cache0.peekEx(e.getKey());
 
@@ -341,7 +348,10 @@
 
             TestKey key1 = entry.key().value(cctx.cacheObjectContext(), true);
 
-            assertSame(key0, key1);
+            if (!binary)
+                assertSame(key0, key1);
+            else
+                assertNotSame(key0, key1);
 
             byte[] val0 = entry.rawGet().value(cctx.cacheObjectContext(), false);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStopSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStopSelfTest.java
index 59c899d..a34857f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStopSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheStopSelfTest.java
@@ -21,36 +21,43 @@
 import java.util.Collection;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
 import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.GridTestUtils;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionConcurrency;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
 import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
 /**
  * Tests correct cache stopping.
  */
 public class GridCacheStopSelfTest extends GridCommonAbstractTest {
-    /** {@inheritDoc} */
-    @Override protected void beforeTest() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1393");
-    }
-
     /** */
     private static final String EXPECTED_MSG = "Cache has been closed or destroyed";
 
     /** */
+    private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
     private boolean atomic;
 
     /** */
@@ -62,7 +69,7 @@
 
         TcpDiscoverySpi disc = new TcpDiscoverySpi();
 
-        disc.setIpFinder(new TcpDiscoveryVmIpFinder(true));
+        disc.setIpFinder(ipFinder);
 
         cfg.setDiscoverySpi(disc);
 
@@ -70,6 +77,9 @@
 
         ccfg.setCacheMode(replicated ? REPLICATED : PARTITIONED);
 
+        if (!replicated)
+            ccfg.setBackups(1);
+
         ccfg.setAtomicityMode(atomic ? ATOMIC : TRANSACTIONAL);
 
         ccfg.setSwapEnabled(true);
@@ -126,6 +136,112 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testStopMultithreaded() throws Exception {
+        try {
+            startGrid(0);
+
+            for (int i = 0; i < 5; i++) {
+                log.info("Iteration: " + i);
+
+                startGridsMultiThreaded(1, 3);
+
+                final AtomicInteger threadIdx = new AtomicInteger(0);
+
+                final IgniteInternalFuture<?> fut1 = GridTestUtils.runMultiThreadedAsync(new Callable<Void>() {
+                    @Override public Void call() throws Exception {
+                        int idx = threadIdx.getAndIncrement();
+
+                        IgniteKernal node = (IgniteKernal)ignite(idx % 3 + 1);
+
+                        IgniteCache<Integer, Integer> cache = node.cache(null);
+
+                        while (true) {
+                            try {
+                                cacheOperations(node, cache);
+                            }
+                            catch (Exception e) {
+                                if (node.isStopping())
+                                    break;
+                            }
+                        }
+
+                        return null;
+                    }
+                }, 20, "tx-node-stop-thread");
+
+                IgniteInternalFuture<?> fut2 = GridTestUtils.runMultiThreadedAsync(new Callable<Void>() {
+                    @Override public Void call() throws Exception {
+                        IgniteKernal node = (IgniteKernal)ignite(0);
+
+                        IgniteCache<Integer, Integer> cache = node.cache(null);
+
+                        while (!fut1.isDone()) {
+                            try {
+                                cacheOperations(node, cache);
+                            }
+                            catch (Exception ignore) {
+                                // No-op.
+                            }
+                        }
+
+                        return null;
+                    }
+                }, 2, "tx-thread");
+
+                Thread.sleep(3000);
+
+                final AtomicInteger nodeIdx = new AtomicInteger(1);
+
+                GridTestUtils.runMultiThreaded(new Callable<Void>() {
+                    @Override public Void call() throws Exception {
+                        int idx = nodeIdx.getAndIncrement();
+
+                        log.info("Stop node: " + idx);
+
+                        ignite(idx).close();
+
+                        return null;
+                    }
+                }, 3, "stop-node");
+
+                fut1.get();
+                fut2.get();
+            }
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /**
+     * @param node Node.
+     * @param cache Cache.
+     */
+    private void cacheOperations(Ignite node, IgniteCache<Integer, Integer> cache) {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+        Integer key = rnd.nextInt(1000);
+
+        cache.put(key, key);
+
+        cache.get(key);
+
+        try (Transaction tx = node.transactions().txStart(OPTIMISTIC, REPEATABLE_READ)) {
+            cache.put(key, key);
+
+            tx.commit();
+        }
+
+        try (Transaction tx = node.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
+            cache.put(key, key);
+
+            tx.commit();
+        }
+    }
+
+    /**
      * @param startTx If {@code true} starts transactions.
      * @throws Exception If failed.
      */
@@ -143,8 +259,10 @@
 
             assertNotNull(cache);
 
-            assertEquals(atomic ? ATOMIC : TRANSACTIONAL, cache.getConfiguration(CacheConfiguration.class).getAtomicityMode());
-            assertEquals(replicated ? REPLICATED : PARTITIONED, cache.getConfiguration(CacheConfiguration.class).getCacheMode());
+            CacheConfiguration ccfg = cache.getConfiguration(CacheConfiguration.class);
+
+            assertEquals(atomic ? ATOMIC : TRANSACTIONAL, ccfg.getAtomicityMode());
+            assertEquals(replicated ? REPLICATED : PARTITIONED, ccfg.getCacheMode());
 
             Collection<IgniteInternalFuture<?>> putFuts = new ArrayList<>();
 
@@ -155,7 +273,9 @@
                     @Override public Void call() throws Exception {
                         try {
                             if (startTx) {
-                                try (Transaction tx = grid(0).transactions().txStart()) {
+                                TransactionConcurrency concurrency = key % 2 == 0 ? OPTIMISTIC : PESSIMISTIC;
+
+                                try (Transaction tx = grid(0).transactions().txStart(concurrency, REPEATABLE_READ)) {
                                     cache.put(key, key);
 
                                     readyLatch.countDown();
@@ -173,12 +293,9 @@
                                 cache.put(key, key);
                             }
                         }
-                        catch (CacheException | IgniteException e) {
+                        catch (CacheException | IgniteException | IllegalStateException e) {
                             log.info("Ignore error: " + e);
                         }
-                        catch (IllegalStateException e) {
-                            assertTrue(e.getMessage().startsWith(EXPECTED_MSG));
-                        }
 
                         return null;
                     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheCopyOnReadDisabledAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheCopyOnReadDisabledAbstractTest.java
index 1c08c0e..a3b362b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheCopyOnReadDisabledAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheCopyOnReadDisabledAbstractTest.java
@@ -57,6 +57,8 @@
 
             TestValue val0 = cache.get(key);
 
+            assertSame(val0, cache.get(key));
+
             assertNotSame(val, val0); // Original user value is always copied.
 
             assertSame(val0, cache.localPeek(key));
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/context/IgniteCacheAbstractExecutionContextTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/context/IgniteCacheAbstractExecutionContextTest.java
index c855c9d..cc4d228 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/context/IgniteCacheAbstractExecutionContextTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/context/IgniteCacheAbstractExecutionContextTest.java
@@ -24,7 +24,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.IgniteCacheAbstractTest;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.GridTestExternalClassLoader;
 import org.apache.ignite.testframework.config.GridTestProperties;
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java
index bc11448..3a5922f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/GridCacheAbstractDataStructuresFailoverSelfTest.java
@@ -54,6 +54,7 @@
 import org.apache.ignite.lang.IgniteCallable;
 import org.apache.ignite.lang.IgniteClosure;
 import org.apache.ignite.resources.IgniteInstanceResource;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.testframework.GridTestUtils;
 
@@ -122,6 +123,8 @@
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
+        ((TcpCommunicationSpi)cfg.getCommunicationSpi()).setSharedMemoryPort(-1);
+
         AtomicConfiguration atomicCfg = new AtomicConfiguration();
 
         atomicCfg.setCacheMode(collectionCacheMode());
@@ -406,280 +409,138 @@
     /**
      * @throws Exception If failed.
      */
-    public void testSemaphoreTopologyChange() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1977");
-
+    public void testSemaphoreFailoverSafe() throws Exception {
         try (IgniteSemaphore semaphore = grid(0).semaphore(STRUCTURE_NAME, 20, true, true)) {
-            try {
-                Ignite g = startGrid(NEW_GRID_NAME);
+            Ignite g = startGrid(NEW_GRID_NAME);
 
-                assert g.semaphore(STRUCTURE_NAME, 20, true, true).availablePermits() == 20;
+            IgniteSemaphore semaphore2 = g.semaphore(STRUCTURE_NAME, 20, true, false);
 
-                g.semaphore(STRUCTURE_NAME, 20, true, true).acquire(10);
+            assertEquals(20, semaphore2.availablePermits());
 
-                stopGrid(NEW_GRID_NAME);
+            semaphore2.acquire(10);
 
-                assert grid(0).semaphore(STRUCTURE_NAME, 20, true, true).availablePermits() == 10;
-            }
-            finally {
-                grid(0).semaphore(STRUCTURE_NAME, 20, true, true).close();
-            }
+            stopGrid(NEW_GRID_NAME);
+
+            assertEquals(10, semaphore.availablePermits());
         }
-
     }
 
     /**
      * @throws Exception If failed.
      */
-    public void testSemaphoreConstantTopologyChange() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1977");
+    public void testSemaphoreNonFailoverSafe() throws Exception {
+        try (IgniteSemaphore sem = grid(0).semaphore(STRUCTURE_NAME, 20, false, true)) {
+            Ignite g = startGrid(NEW_GRID_NAME);
 
-        try (IgniteSemaphore s = grid(0).semaphore(STRUCTURE_NAME, 10, false, true)) {
-            try {
-                IgniteInternalFuture<?> fut = GridTestUtils.runMultiThreadedAsync(new CA() {
-                    @Override public void apply() {
-                        try {
-                            for (int i = 0; i < TOP_CHANGE_CNT; i++) {
-                                String name = UUID.randomUUID().toString();
+            IgniteSemaphore sem2 = g.semaphore(STRUCTURE_NAME, 20, false, false);
 
-                                try {
-                                    Ignite g = startGrid(name);
+            sem2.acquire(20);
 
-                                    assert g.semaphore(STRUCTURE_NAME, 10, false, false) != null;
-                                }
-                                finally {
-                                    if (i != TOP_CHANGE_CNT - 1)
-                                        stopGrid(name);
-                                }
-                            }
-                        }
-                        catch (Exception e) {
-                            throw F.wrap(e);
-                        }
-                    }
-                }, TOP_CHANGE_THREAD_CNT, "topology-change-thread");
+            assertEquals(0, sem.availablePermits());
 
-                int val = s.availablePermits();
-
-                while (!fut.isDone()) {
-                    assert s.availablePermits() == val;
-
-                    s.acquire();
-
-                    assert s.availablePermits() == val - 1;
-
-                    s.release();
+            new Timer().schedule(new TimerTask() {
+                @Override public void run() {
+                    stopGrid(NEW_GRID_NAME);
                 }
+            }, 2000);
 
-                fut.get();
-
-                for (Ignite g : G.allGrids())
-                    assert g.semaphore(STRUCTURE_NAME, 0, false, true).availablePermits() == val;
+            try {
+                sem.acquire(1);
             }
-            finally {
-                grid(0).semaphore(STRUCTURE_NAME, 0, false, true).close();
+            catch (IgniteInterruptedException e) {
+                // Expected exception.
+                return;
             }
         }
+
+        fail("Thread hasn't been interrupted");
     }
 
     /**
-     * This method tests if permits are successfully reassigned when a node fails in failoverSafe mode.
-     *
      * @throws Exception If failed.
      */
     public void testSemaphoreConstantTopologyChangeFailoverSafe() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1977");
-
-        try (IgniteSemaphore s = grid(0).semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true)) {
-            try {
-                IgniteInternalFuture<?> fut = GridTestUtils.runMultiThreadedAsync(new CA() {
-                    @Override public void apply() {
-                        try {
-                            for (int i = 0; i < TOP_CHANGE_CNT; i++) {
-                                String name = UUID.randomUUID().toString();
-
-                                try {
-                                    Ignite g = startGrid(name);
-
-                                    final IgniteSemaphore sem = g.semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true);
-
-                                    assertNotNull(sem);
-
-                                    sem.acquire();
-
-                                    if (i == TOP_CHANGE_CNT - 1) {
-                                        sem.release();
-                                    }
-                                }
-                                finally {
-                                    if (i != TOP_CHANGE_CNT - 1) {
-                                        stopGrid(name);
-                                    }
-                                }
-                            }
-                        }
-                        catch (Exception e) {
-                            throw F.wrap(e);
-                        }
-                    }
-                }, TOP_CHANGE_THREAD_CNT, "topology-change-thread");
-
-                while (!fut.isDone()) {
-                    s.release();
-
-                    s.acquire();
-                }
-
-                fut.get();
-
-                int val = s.availablePermits();
-
-                assertEquals(val, TOP_CHANGE_CNT);
-
-                for (Ignite g : G.allGrids())
-                    assertEquals(val, g.semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true).availablePermits());
-            }
-            finally {
-                grid(0).semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true).close();
-            }
-        }
+        doTestSemaphore(new ConstantTopologyChangeWorker(), true);
     }
 
     /**
-     * This method tests if permits are successfully reassigned when multiple nodes fail in failoverSafe mode.
-     *
      * @throws Exception If failed.
      */
-    public void testSemaphoreConstantMultipleTopologyChangeFailoverSafe() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1977");
-
-        final int numPermits = 3;
-
-        try (IgniteSemaphore s = grid(0).semaphore(STRUCTURE_NAME, numPermits, true, true)) {
-            try {
-                IgniteInternalFuture<?> fut = GridTestUtils.runMultiThreadedAsync(new CA() {
-                    @Override public void apply() {
-                        try {
-                            for (int i = 0; i < TOP_CHANGE_CNT; i++) {
-                                Collection<String> names = new GridLeanSet<>(3);
-
-                                try {
-                                    for (int j = 0; j < numPermits; j++) {
-                                        String name = UUID.randomUUID().toString();
-
-                                        names.add(name);
-
-                                        Ignite g = startGrid(name);
-
-                                        final IgniteSemaphore sem = g.semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true);
-
-                                        assertNotNull(sem);
-
-                                        sem.acquire();
-
-                                        if (i == TOP_CHANGE_CNT - 1) {
-                                            sem.release();
-                                        }
-                                    }
-                                }
-                                finally {
-                                    if (i != TOP_CHANGE_CNT - 1)
-                                        for (String name : names) {
-                                            stopGrid(name);
-
-                                            awaitPartitionMapExchange();
-                                        }
-                                }
-                            }
-                        }
-                        catch (Exception e) {
-                            throw F.wrap(e);
-                        }
-                    }
-                }, TOP_CHANGE_THREAD_CNT, "topology-change-thread");
-
-                while (!fut.isDone()) {
-                    s.release();
-
-                    s.acquire();
-                }
-
-                fut.get();
-
-                int val = s.availablePermits();
-
-                assertEquals(val, numPermits);
-
-                for (Ignite g : G.allGrids())
-                    assertEquals(val, g.semaphore(STRUCTURE_NAME, 0, true, true).availablePermits());
-            }
-            finally {
-                grid(0).semaphore(STRUCTURE_NAME, 0, true, true).close();
-            }
-        }
+    public void testSemaphoreConstantTopologyChangeNonFailoverSafe() throws Exception {
+        doTestSemaphore(new ConstantTopologyChangeWorker(), false);
     }
 
     /**
-     * This method test if exception is thrown when node fails in non FailoverSafe mode.
-     *
      * @throws Exception If failed.
      */
-    public void testSemaphoreConstantTopologyChangeNotFailoverSafe() throws Exception {
+    public void testSemaphoreMultipleTopologyChangeFailoverSafe() throws Exception {
+        doTestSemaphore(multipleTopologyChangeWorker(), true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testSemaphoreMultipleTopologyChangeNonFailoverSafe() throws Exception {
+        doTestSemaphore(multipleTopologyChangeWorker(), false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    private void doTestSemaphore(ConstantTopologyChangeWorker topWorker, final boolean failoverSafe) throws Exception {
         fail("https://issues.apache.org/jira/browse/IGNITE-1977");
 
-        try (IgniteSemaphore s = grid(0).semaphore(STRUCTURE_NAME, 1, false, true)) {
-            try {
-                IgniteInternalFuture<?> fut = GridTestUtils.runMultiThreadedAsync(new CA() {
-                    @Override public void apply() {
+        final int permits = topWorker instanceof MultipleTopologyChangeWorker ||
+            topWorker instanceof PartitionedMultipleTopologyChangeWorker ? TOP_CHANGE_THREAD_CNT * 3 :
+            TOP_CHANGE_CNT;
+
+        try (IgniteSemaphore s = grid(0).semaphore(STRUCTURE_NAME, permits, failoverSafe, true)) {
+            IgniteInternalFuture<?> fut = topWorker.startChangingTopology(new IgniteClosure<Ignite, Object>() {
+                @Override public Object apply(Ignite ignite) {
+                    IgniteSemaphore sem = ignite.semaphore(STRUCTURE_NAME, permits, failoverSafe, false);
+
+                    while (true) {
                         try {
-                            for (int i = 0; i < 2; i++) {
-                                String name = UUID.randomUUID().toString();
+                            sem.acquire(1);
 
-                                try {
-                                    Ignite g = startGrid(name);
-
-                                    final IgniteSemaphore sem = g.semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true);
-
-                                    assertNotNull(sem);
-
-                                    if (i != 1) {
-                                        sem.acquire();
-                                    }
-
-                                }
-                                finally {
-                                    if (i != 1) {
-                                        stopGrid(name);
-                                    }
-                                }
-                            }
-
+                            break;
                         }
-                        catch (Exception e) {
-                            throw F.wrap(e);
+                        catch (IgniteInterruptedException e) {
+                            // Exception may happen in non failover safe mode.
+                            if (failoverSafe)
+                                throw e;
                         }
                     }
-                }, TOP_CHANGE_THREAD_CNT, "topology-change-thread");
 
-                while (s.availablePermits() != 0) {
-                    // Wait for semaphore to be acquired.
+                    return null;
+                }
+            });
+
+            while (!fut.isDone()) {
+                while (true) {
+                    try {
+                        s.acquire(1);
+
+                        break;
+                    }
+                    catch (IgniteInterruptedException e) {
+                        // Exception may happen in non failover safe mode.
+                        if (failoverSafe)
+                            throw e;
+                    }
                 }
 
-                try {
-                    s.acquire();
-                    fail("In non-FailoverSafe mode IgniteInterruptedCheckedException must be thrown.");
-                }
-                catch (Exception e) {
-                    assert (e instanceof IgniteInterruptedException);
-                }
+                assert s.availablePermits() < permits;
 
-                assertTrue(s.isBroken());
+                s.release();
 
-                fut.get();
+                assert s.availablePermits() <= permits;
             }
-            finally {
-                grid(0).semaphore(STRUCTURE_NAME, TOP_CHANGE_CNT, true, true).close();
-            }
+
+            fut.get();
+
+            for (Ignite g : G.allGrids())
+                assertEquals(permits, g.semaphore(STRUCTURE_NAME, permits, false, false).availablePermits());
         }
     }
 
@@ -1010,8 +871,7 @@
                                 callback.apply(g);
                             }
                             finally {
-                                if (i != TOP_CHANGE_CNT - 1)
-                                    stopGrid(name);
+                                stopGrid(name);
                             }
                         }
                     }
@@ -1060,10 +920,8 @@
                                 }
                             }
                             finally {
-                                if (i != TOP_CHANGE_CNT - 1) {
-                                    for (String name : names)
-                                        stopGrid(name);
-                                }
+                                for (String name : names)
+                                    stopGrid(name);
                             }
                         }
                     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteCollectionAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteCollectionAbstractTest.java
index 36c846a..3e38a58 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteCollectionAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteCollectionAbstractTest.java
@@ -26,6 +26,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.datastructures.GridCacheQueueAdapter;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
@@ -45,6 +46,8 @@
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
+        ((TcpCommunicationSpi)cfg.getCommunicationSpi()).setSharedMemoryPort(-1);
+
         TcpDiscoverySpi spi = new TcpDiscoverySpi();
 
         spi.setIpFinder(ipFinder);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java
new file mode 100644
index 0000000..e53650c
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteBinaryMetadataUpdateChangingTopologySelfTest.java
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.distributed;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteNodeAttributes;
+import org.apache.ignite.internal.managers.communication.GridIoMessage;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxPrepareResponse;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.resources.LoggerResource;
+import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Tests specific scenario when binary metadata should be updated from a system thread
+ * and topology has been already changed since the original transaction start.
+ */
+public class IgniteBinaryMetadataUpdateChangingTopologySelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        cfg.setMarshaller(null);
+
+        CacheConfiguration ccfg = new CacheConfiguration("cache");
+
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+        ccfg.setBackups(1);
+
+        cfg.setCacheConfiguration(ccfg);
+
+        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
+
+        discoSpi.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(discoSpi);
+
+        cfg.setCommunicationSpi(new TestCommunicationSpi());
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrids(4);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testNoDeadlockOptimistic() throws Exception {
+        int key1 = primaryKey(ignite(1).cache("cache"));
+        int key2 = primaryKey(ignite(2).cache("cache"));
+
+        TestCommunicationSpi spi = (TestCommunicationSpi)ignite(1).configuration().getCommunicationSpi();
+
+        spi.blockMessages(GridNearTxPrepareResponse.class, ignite(0).cluster().localNode().id());
+
+        IgniteCache<Object, Object> cache = ignite(0).cache("cache").withAsync();
+
+        cache.putAll(F.asMap(key1, "val1", key2, new TestValue()));
+
+        try {
+            Thread.sleep(500);
+
+            IgniteInternalFuture<Void> fut = GridTestUtils.runAsync(new Callable<Void>() {
+                @Override public Void call() throws Exception {
+                    startGrid(4);
+
+                    return null;
+                }
+            });
+
+            Thread.sleep(500);
+
+            spi.stopBlock();
+
+            cache.future().get();
+
+            fut.get();
+        }
+        finally {
+            stopGrid(4);
+        }
+    }
+
+    /**
+     *
+     */
+    private static class TestCommunicationSpi extends TcpCommunicationSpi {
+        /** */
+        @LoggerResource
+        private IgniteLogger log;
+
+        /** */
+        private List<T2<ClusterNode, GridIoMessage>> blockedMsgs = new ArrayList<>();
+
+        /** */
+        private Map<Class<?>, Set<UUID>> blockCls = new HashMap<>();
+
+        /** */
+        private Class<?> recordCls;
+
+        /** */
+        private List<Object> recordedMsgs = new ArrayList<>();
+
+        /** {@inheritDoc} */
+        @Override public void sendMessage(ClusterNode node, Message msg, IgniteInClosure<IgniteException> ackClosure)
+            throws IgniteSpiException {
+            if (msg instanceof GridIoMessage) {
+                Object msg0 = ((GridIoMessage)msg).message();
+
+                synchronized (this) {
+                    if (recordCls != null && msg0.getClass().equals(recordCls))
+                        recordedMsgs.add(msg0);
+
+                    Set<UUID> blockNodes = blockCls.get(msg0.getClass());
+
+                    if (F.contains(blockNodes, node.id())) {
+                        log.info("Block message [node=" + node.attribute(IgniteNodeAttributes.ATTR_GRID_NAME) +
+                            ", msg=" + msg0 + ']');
+
+                        blockedMsgs.add(new T2<>(node, (GridIoMessage)msg));
+
+                        return;
+                    }
+                }
+            }
+
+            super.sendMessage(node, msg, ackClosure);
+        }
+
+        /**
+         * @param recordCls Message class to record.
+         */
+        void record(@Nullable Class<?> recordCls) {
+            synchronized (this) {
+                this.recordCls = recordCls;
+            }
+        }
+
+        /**
+         * @return Recorded messages.
+         */
+        List<Object> recordedMessages() {
+            synchronized (this) {
+                List<Object> msgs = recordedMsgs;
+
+                recordedMsgs = new ArrayList<>();
+
+                return msgs;
+            }
+        }
+
+        /**
+         * @param cls Message class.
+         * @param nodeId Node ID.
+         */
+        void blockMessages(Class<?> cls, UUID nodeId) {
+            synchronized (this) {
+                Set<UUID> set = blockCls.get(cls);
+
+                if (set == null) {
+                    set = new HashSet<>();
+
+                    blockCls.put(cls, set);
+                }
+
+                set.add(nodeId);
+            }
+        }
+
+        /**
+         *
+         */
+        void stopBlock() {
+            synchronized (this) {
+                blockCls.clear();
+
+                for (T2<ClusterNode, GridIoMessage> msg : blockedMsgs) {
+                    ClusterNode node = msg.get1();
+
+                    log.info("Send blocked message: [node=" + node.attribute(IgniteNodeAttributes.ATTR_GRID_NAME) +
+                        ", msg=" + msg.get2().message() + ']');
+
+                    sendMessage(msg.get1(), msg.get2());
+                }
+
+                blockedMsgs.clear();
+            }
+        }
+    }
+
+    private static class TestValue {
+        /** Field1. */
+        private String field1;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java
index 00b7c0f..1738a0d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteCacheSizeFailoverTest.java
@@ -63,6 +63,13 @@
         return cfg;
     }
 
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+    }
+
     /**
      * @throws Exception If failed.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtInternalEntrySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtInternalEntrySelfTest.java
deleted file mode 100644
index 0f4fe5d..0000000
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridCacheDhtInternalEntrySelfTest.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.processors.cache.distributed.dht;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import org.apache.ignite.cache.CachePeekMode;
-import org.apache.ignite.cache.CacheWriteSynchronizationMode;
-import org.apache.ignite.cache.affinity.Affinity;
-import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
-import org.apache.ignite.cluster.ClusterNode;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.configuration.NearCacheConfiguration;
-import org.apache.ignite.internal.processors.cache.GridCacheAlwaysEvictionPolicy;
-import org.apache.ignite.internal.processors.datastructures.GridCacheInternalKeyImpl;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.lang.IgniteBiTuple;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
-import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
-
-import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
-import static org.apache.ignite.cache.CacheMode.PARTITIONED;
-import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
-
-/**
- * Tests for internal DHT entry.
- */
-public class GridCacheDhtInternalEntrySelfTest extends GridCommonAbstractTest {
-    /** IP finder. */
-    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
-
-    /** Grid count. */
-    private static final int GRID_CNT = 2;
-
-    /** Atomic long name. */
-    private static final String ATOMIC_LONG_NAME = "test.atomic.long";
-
-    /** {@inheritDoc} */
-    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
-        IgniteConfiguration cfg = super.getConfiguration(gridName);
-
-        TcpDiscoverySpi spi = new TcpDiscoverySpi();
-
-        spi.setIpFinder(IP_FINDER);
-
-        cfg.setDiscoverySpi(spi);
-
-        CacheConfiguration cacheCfg = defaultCacheConfiguration();
-
-        cacheCfg.setCacheMode(PARTITIONED);
-        cacheCfg.setRebalanceMode(SYNC);
-        cacheCfg.setAffinity(new RendezvousAffinityFunction(false, 2));
-        cacheCfg.setBackups(0);
-        cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
-
-        NearCacheConfiguration nearCfg = new NearCacheConfiguration();
-        nearCfg.setNearEvictionPolicy(new GridCacheAlwaysEvictionPolicy());
-        cacheCfg.setNearConfiguration(nearCfg);
-
-        cacheCfg.setAtomicityMode(TRANSACTIONAL);
-
-        cfg.setCacheConfiguration(cacheCfg);
-
-        return cfg;
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        startGridsMultiThreaded(GRID_CNT);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        stopAllGrids();
-    }
-
-    /** @throws Exception If failed. */
-    public void testInternalKeyReaders() throws Exception {
-        IgniteBiTuple<ClusterNode, ClusterNode> nodes = getNodes(ATOMIC_LONG_NAME);
-
-        ClusterNode primary = nodes.get1();
-        ClusterNode other = nodes.get2();
-
-        // Create on non-primary node.
-        grid(other).cache(null).put(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME), 1);
-
-        check(primary, other, true);
-
-        // Update on primary.
-        grid(primary).cache(null).put(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME), 2);
-
-        // Check on non-primary.
-        assertEquals(2, grid(other).cache(null).get(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME)));
-
-        check(primary, other, true);
-
-        // Remove.
-        assert grid(other).cache(null).remove(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME));
-
-        check(primary, other, false);
-    }
-
-    /**
-     * @param primary Primary node.
-     * @param other Non-primary node.
-     * @param exists Whether entry is expected to exist.
-     * @throws Exception In case of error.
-     */
-    private void check(ClusterNode primary, ClusterNode other, boolean exists) throws Exception {
-        if (exists) {
-            // Check primary node has entry in DHT cache.
-            assert peekNear(primary) == null;
-            assert peekDht(primary) != null;
-
-            // Check non-primary node has entry in near cache.
-            assert peekNear(other) != null;
-            assert peekDht(other) == null;
-
-            // Check primary node has reader for non-primary node.
-            assert peekDhtEntry(primary).readers().contains(other.id());
-        }
-        else {
-            assert peekGlobal(primary) == null;
-            assert peekGlobal(other) == null;
-        }
-    }
-
-    /**
-     * @param node Node.
-     * @return Atomic long value.
-     */
-    private Object peekGlobal(ClusterNode node) {
-        return grid(node).cache(null).localPeek(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME), CachePeekMode.ONHEAP);
-    }
-
-    /**
-     * @param node Node.
-     * @return Atomic long value.
-     */
-    private Object peekNear(ClusterNode node) {
-        return grid(node).cache(null).localPeek(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME), CachePeekMode.NEAR);
-    }
-
-    /**
-     * @param node Node.
-     * @return Atomic long value.
-     */
-    private Object peekDht(ClusterNode node) {
-        return grid(node).cache(null).localPeek(new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME), CachePeekMode.BACKUP,
-            CachePeekMode.PRIMARY);
-    }
-
-    /**
-     * @param node Node.
-     * @return DHT entry.
-     */
-    private GridDhtCacheEntry peekDhtEntry(ClusterNode node) {
-        return (GridDhtCacheEntry)dht(grid(node).cache(null)).peekEx(
-            new GridCacheInternalKeyImpl(ATOMIC_LONG_NAME));
-    }
-
-    /**
-     * @param key Key.
-     * @return Pair {primary node, some other node}.
-     */
-    private IgniteBiTuple<ClusterNode, ClusterNode> getNodes(String key) {
-        Affinity<Object> aff = grid(0).affinity(null);
-
-        ClusterNode primary = aff.mapKeyToNode(key);
-
-        assert primary != null;
-
-        Collection<ClusterNode> nodes = new ArrayList<>(grid(0).cluster().nodes());
-
-        nodes.remove(primary);
-
-        ClusterNode other = F.first(nodes);
-
-        assert other != null;
-
-        assert !F.eqNodes(primary, other);
-
-        return F.t(primary, other);
-    }
-}
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java
index c00557d..74cb9ef 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteAtomicLongChangingTopologySelfTest.java
@@ -31,7 +31,9 @@
 import java.util.concurrent.atomic.AtomicReferenceArray;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteAtomicLong;
+import org.apache.ignite.IgniteClientDisconnectedException;
 import org.apache.ignite.IgniteQueue;
+import org.apache.ignite.IgniteSet;
 import org.apache.ignite.configuration.AtomicConfiguration;
 import org.apache.ignite.configuration.CollectionConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
@@ -56,7 +58,7 @@
     /** Grid count. */
     private static final int GRID_CNT = 5;
 
-    /** Restart cound. */
+    /** Restart count. */
     private static final int RESTART_CNT = 15;
 
     /** Atomic long name. */
@@ -91,6 +93,8 @@
 
         cfg.setClientMode(client);
 
+        cfg.setPeerClassLoadingEnabled(false);
+
         return cfg;
     }
 
@@ -133,8 +137,6 @@
      * @throws Exception If failed.
      */
     public void testClientAtomicLongCreateCloseFailover() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1732");
-
         testFailoverWithClient(new IgniteInClosure<Ignite>() {
             @Override public void apply(Ignite ignite) {
                 for (int i = 0; i < 100; i++) {
@@ -150,8 +152,6 @@
      * @throws Exception If failed.
      */
     public void testClientQueueCreateCloseFailover() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-1976");
-
         testFailoverWithClient(new IgniteInClosure<Ignite>() {
             @Override public void apply(Ignite ignite) {
                 for (int i = 0; i < 100; i++) {
@@ -170,6 +170,27 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testClientSetCreateCloseFailover() throws Exception {
+        testFailoverWithClient(new IgniteInClosure<Ignite>() {
+            @Override public void apply(Ignite ignite) {
+                for (int i = 0; i < 100; i++) {
+                    CollectionConfiguration colCfg = new CollectionConfiguration();
+
+                    colCfg.setBackups(1);
+                    colCfg.setCacheMode(PARTITIONED);
+                    colCfg.setAtomicityMode(i % 2 == 0 ? TRANSACTIONAL : ATOMIC);
+
+                    IgniteSet set = ignite.set("set-" + i, colCfg);
+
+                    set.close();
+                }
+            }
+        });
+    }
+
+    /**
      * @param c Test iteration closure.
      * @throws Exception If failed.
      */
@@ -188,7 +209,7 @@
 
         IgniteInternalFuture<?> fut = restartThread(finished);
 
-        long stop = System.currentTimeMillis() + 30_000;
+        long stop = System.currentTimeMillis() + 60_000;
 
         try {
             int iter = 0;
@@ -196,7 +217,12 @@
             while (System.currentTimeMillis() < stop) {
                 log.info("Iteration: " + iter++);
 
-                c.apply(ignite);
+                try {
+                    c.apply(ignite);
+                }
+                catch (IgniteClientDisconnectedException e) {
+                    e.reconnectFuture().get();
+                }
             }
 
             finished.set(true);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java
index e46761b..0294dea 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheCrossCacheTxFailoverTest.java
@@ -37,6 +37,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
@@ -391,6 +392,11 @@
             ignite0.destroyCache(CACHE1);
             ignite0.destroyCache(CACHE2);
 
+            AffinityTopologyVersion topVer = ignite0.context().cache().context().exchange().lastTopologyFuture().get();
+
+            for (Ignite ignite : G.allGrids())
+                ((IgniteKernal)ignite).context().cache().context().exchange().affinityReadyFuture(topVer).get();
+
             awaitPartitionMapExchange();
         }
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java
index ee28cf9..4eb8a6b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePutRetryAbstractSelfTest.java
@@ -110,6 +110,8 @@
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
+        cfg.setIncludeEventTypes();
+
         ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
 
         ((TcpCommunicationSpi)cfg.getCommunicationSpi()).setSharedMemoryPort(-1);
@@ -122,6 +124,8 @@
 
         cfg.setSwapSpaceSpi(new GridTestSwapSpaceSpi());
 
+        cfg.setIncludeEventTypes(new int[0]);
+
         return cfg;
     }
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxForceKeyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxForceKeyTest.java
index 348597e..84886d3 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxForceKeyTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxForceKeyTest.java
@@ -70,7 +70,7 @@
 
         Ignite ignite1 = startGrid(1);
 
-        final Integer key = 2;
+        final Integer key = primaryKey(ignite1.cache(null));
 
         assertNull(cache.getAndPut(key, key));
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedPreloadLifecycleSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedPreloadLifecycleSelfTest.java
index ca4f24e..e434b49 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedPreloadLifecycleSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedPreloadLifecycleSelfTest.java
@@ -182,39 +182,7 @@
 
                 CacheQuery<Map.Entry<Object, MyValue>> qry = c2.context().queries().createScanQuery(null, null, false);
 
-                int totalCnt = F.sumInt(qry.execute(new IgniteReducer<Map.Entry<Object, MyValue>, Integer>() {
-                    @IgniteInstanceResource
-                    private Ignite grid;
-
-                    private int cnt;
-
-                    @Override public boolean collect(Map.Entry<Object, MyValue> e) {
-                        Object key = e.getKey();
-
-                        assertNotNull(e.getValue());
-
-                        try {
-                            Object v1 = e.getValue();
-                            Object v2 = grid.cache("one").get(key);
-
-                            assertNotNull(v2);
-                            assertEquals(v1, v2);
-                        }
-                        catch (CacheException e1) {
-                            e1.printStackTrace();
-
-                            assert false;
-                        }
-
-                        cnt++;
-
-                        return true;
-                    }
-
-                    @Override public Integer reduce() {
-                        return cnt;
-                    }
-                }).get());
+                int totalCnt = F.sumInt(qry.execute(new EntryIntegerIgniteReducer()).get());
 
                 info("Total entry count [grid=" + j + ", totalCnt=" + totalCnt + ']');
 
@@ -278,4 +246,41 @@
     public void testScanQuery4() throws Exception {
         checkScanQuery(keys(false, 500));
     }
+
+    /**
+     *
+     */
+    private static class EntryIntegerIgniteReducer implements IgniteReducer<Map.Entry<Object, MyValue>, Integer> {
+        @IgniteInstanceResource
+        private Ignite grid;
+
+        private int cnt;
+
+        @Override public boolean collect(Map.Entry<Object, MyValue> e) {
+            Object key = e.getKey();
+
+            assertNotNull(e.getValue());
+
+            try {
+                Object v1 = e.getValue();
+                Object v2 = grid.cache("one").get(key);
+
+                assertNotNull(v2);
+                assertEquals(v1, v2);
+            }
+            catch (CacheException e1) {
+                e1.printStackTrace();
+
+                assert false;
+            }
+
+            cnt++;
+
+            return true;
+        }
+
+        @Override public Integer reduce() {
+            return cnt;
+        }
+    }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridReplicatedTxPreloadTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridReplicatedTxPreloadTest.java
index e7560c72..126ce61 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridReplicatedTxPreloadTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/GridReplicatedTxPreloadTest.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache.distributed.replicated;
 
 import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteTxPreloadAbstractTest;
 
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
@@ -32,6 +33,11 @@
     }
 
     /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        return super.getConfiguration(gridName).setMarshaller(null);
+    }
+
+    /** {@inheritDoc} */
     @Override public void testLocalTxPreloadingOptimistic() throws Exception {
         fail("https://issues.apache.org/jira/browse/IGNITE-1755");
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadLifecycleSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadLifecycleSelfTest.java
index fcaafd7..6a7a68b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadLifecycleSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/replicated/preloader/GridCacheReplicatedPreloadLifecycleSelfTest.java
@@ -192,46 +192,7 @@
 
                 qry = qry.projection(grid(j).cluster());
 
-                int totalCnt = F.sumInt(qry.execute(new IgniteReducer<Map.Entry<Object, MyValue>, Integer>() {
-                    @IgniteInstanceResource
-                    private Ignite grid;
-
-                    @LoggerResource
-                    private IgniteLogger log0;
-
-                    private int cnt;
-
-                    @Override public boolean collect(Map.Entry<Object, MyValue> e) {
-                        if (!quiet && log0.isInfoEnabled())
-                            log0.info("Collecting entry: " + e);
-
-                        Object key = e.getKey();
-
-                        assertNotNull(e.getValue());
-
-                        try {
-                            Object v1 = e.getValue();
-                            Object v2 = ((IgniteKernal)grid).getCache("one").get(key);
-
-                            assertNotNull("Cache c1 misses value for key [i=" + j0 + ", j=" + i0 + ", missedKey=" +
-                                key + ", cache=" + ((IgniteKernal)grid).getCache("one").values() + ']', v2);
-                            assertEquals(v1, v2);
-                        }
-                        catch (IgniteCheckedException e1) {
-                            e1.printStackTrace();
-
-                            assert false;
-                        }
-
-                        cnt++;
-
-                        return true;
-                    }
-
-                    @Override public Integer reduce() {
-                        return cnt;
-                    }
-                }).get());
+                int totalCnt = F.sumInt(qry.execute(new EntryReducer(j0, i0)).get());
 
                 info("Total entry count [grid=" + j + ", totalCnt=" + totalCnt + ']');
 
@@ -295,4 +256,63 @@
     public void testScanQuery4() throws Exception {
         checkScanQuery(keys(false, 500));
     }
+
+    private static class EntryReducer implements IgniteReducer<Map.Entry<Object, MyValue>, Integer> {
+        /** */
+        private final int j0;
+
+        /** */
+        private final int i0;
+
+        /** */
+        @IgniteInstanceResource
+        private Ignite grid;
+
+        /** */
+        @LoggerResource
+        private IgniteLogger log0;
+
+        /** */
+        private int cnt;
+
+        /**
+         */
+        public EntryReducer(int j0, int i0) {
+            this.j0 = j0;
+            this.i0 = i0;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean collect(Map.Entry<Object, MyValue> e) {
+            if (!quiet && log0.isInfoEnabled())
+                log0.info("Collecting entry: " + e);
+
+            Object key = e.getKey();
+
+            assertNotNull(e.getValue());
+
+            try {
+                Object v1 = e.getValue();
+                Object v2 = ((IgniteKernal)grid).getCache("one").get(key);
+
+                assertNotNull("Cache c1 misses value for key [i=" + j0 + ", j=" + i0 + ", missedKey=" +
+                    key + ", cache=" + ((IgniteKernal)grid).getCache("one").values() + ']', v2);
+                assertEquals(v1, v2);
+            }
+            catch (IgniteCheckedException e1) {
+                e1.printStackTrace();
+
+                assert false;
+            }
+
+            cnt++;
+
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        @Override public Integer reduce() {
+            return cnt;
+        }
+    }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionLockUnlockSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionLockUnlockSelfTest.java
index 11faca3..75f5c8f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionLockUnlockSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionLockUnlockSelfTest.java
@@ -142,7 +142,7 @@
                 assertEquals(gridCnt, touchCnt.get());
 
                 for (int j = 0; j < gridCnt; j++)
-                    assertFalse(jcache(j).containsKey("key"));
+                    assertEquals(0, jcache(j).size());
             }
         }
         finally {
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/random/RandomEvictionPolicySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/random/RandomEvictionPolicySelfTest.java
index 9d781eb..af04cdc 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/random/RandomEvictionPolicySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/random/RandomEvictionPolicySelfTest.java
@@ -92,7 +92,11 @@
                     info("Stats [cntr=" + i + ", total=" + runs + ']');
             }
 
-            assert g.cache(null).size() <= max;
+            int size = g.cache(null).size();
+
+            info("Cache size: " + size);
+
+            assert size <= (max * 1.2) : size; // Add 20% room for random evictions.
 
             info(policy(0));
         }
@@ -354,4 +358,4 @@
     @Override protected void checkPolicies() {
         // No-op.
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractDataStreamerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractDataStreamerSelfTest.java
index 7ee6cb6..3938bc6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractDataStreamerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractDataStreamerSelfTest.java
@@ -31,7 +31,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.IgniteInternalFuture;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.Binarylizable;
 import org.apache.ignite.binary.BinaryReader;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractMultiThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractMultiThreadedSelfTest.java
index 5fb02b6..321194f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractMultiThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractMultiThreadedSelfTest.java
@@ -33,13 +33,16 @@
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.Binarylizable;
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.binary.BinaryReader;
 import org.apache.ignite.binary.BinaryTypeConfiguration;
 import org.apache.ignite.binary.BinaryWriter;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.jsr166.LongAdder8;
 
@@ -50,6 +53,9 @@
  */
 public abstract class GridCacheBinaryObjectsAbstractMultiThreadedSelfTest extends GridCommonAbstractTest {
     /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
     private static final int THREAD_CNT = 64;
 
     /** */
@@ -59,6 +65,8 @@
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
+
         CacheConfiguration cacheCfg = new CacheConfiguration();
 
         cacheCfg.setCacheMode(cacheMode());
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractSelfTest.java
index 3925045..29b7204 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheBinaryObjectsAbstractSelfTest.java
@@ -46,7 +46,7 @@
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiInClosure;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectBuilder;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.Binarylizable;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataMultinodeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataMultinodeTest.java
index 99e2073..8823776 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataMultinodeTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataMultinodeTest.java
@@ -33,7 +33,7 @@
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectBuilder;
 import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
@@ -158,7 +158,7 @@
 
             IgniteBinary portables = ignite(i).binary();
 
-            Collection<BinaryType> metaCol = portables.metadata();
+            Collection<BinaryType> metaCol = portables.types();
 
             assertEquals(allTypes.size(), metaCol.size());
 
@@ -238,13 +238,13 @@
 
             GridTestUtils.waitForCondition(new GridAbsPredicate() {
                 @Override public boolean apply() {
-                    Collection<BinaryType> metaCol = p0.metadata();
+                    Collection<BinaryType> metaCol = p0.types();
 
                     return metaCol.size() == 1000;
                 }
             }, getTestTimeout());
 
-            Collection<BinaryType> metaCol = portables.metadata();
+            Collection<BinaryType> metaCol = portables.types();
 
             assertEquals(1000, metaCol.size());
 
@@ -290,6 +290,6 @@
             cache.put(i, builder.build());
         }
 
-        assertEquals(100, ignite(0).binary().metadata().size());
+        assertEquals(100, ignite(0).binary().types().size());
     }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataTest.java
index 256e5fd..f73916d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCacheClientNodeBinaryObjectMetadataTest.java
@@ -30,7 +30,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
@@ -118,8 +118,8 @@
                 aff0.mapKeyToPrimaryAndBackups(obj2));
         }
 
-        Collection<BinaryType> meta1 = ignite1.binary().metadata();
-        Collection<BinaryType> meta2 = ignite1.binary().metadata();
+        Collection<BinaryType> meta1 = ignite1.binary().types();
+        Collection<BinaryType> meta2 = ignite1.binary().types();
 
         assertEquals(meta1.size(), meta2.size());
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCachePortableStoreAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCachePortableStoreAbstractSelfTest.java
index d3df9b7..892a891 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCachePortableStoreAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridCachePortableStoreAbstractSelfTest.java
@@ -28,7 +28,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableCacheEntryMemorySizeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableCacheEntryMemorySizeSelfTest.java
index 30a7ca5..a965588 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableCacheEntryMemorySizeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableCacheEntryMemorySizeSelfTest.java
@@ -25,7 +25,7 @@
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableDuplicateIndexObjectsAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableDuplicateIndexObjectsAbstractSelfTest.java
index b01a363..d15f321 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableDuplicateIndexObjectsAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/GridPortableDuplicateIndexObjectsAbstractSelfTest.java
@@ -31,7 +31,7 @@
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObject;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/DataStreamProcessorPortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/DataStreamProcessorPortableSelfTest.java
index 3777a20..0599863 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/DataStreamProcessorPortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/DataStreamProcessorPortableSelfTest.java
@@ -23,7 +23,7 @@
 import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.datastreamer.DataStreamProcessorSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.stream.StreamReceiver;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/GridDataStreamerImplSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/GridDataStreamerImplSelfTest.java
index 6ce5961..72f71b6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/GridDataStreamerImplSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/datastreaming/GridDataStreamerImplSelfTest.java
@@ -30,7 +30,7 @@
 import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.binary.Binarylizable;
 import org.apache.ignite.binary.BinaryObject;
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheAffinityRoutingPortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheAffinityRoutingPortableSelfTest.java
index c18260b..a6ff3ff 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheAffinityRoutingPortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheAffinityRoutingPortableSelfTest.java
@@ -22,7 +22,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheAffinityRoutingSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryTypeConfiguration;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheMemoryModePortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheMemoryModePortableSelfTest.java
index 0f3e67c..71cf106 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheMemoryModePortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheMemoryModePortableSelfTest.java
@@ -19,7 +19,7 @@
 
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheMemoryModeSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  * Memory models test.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredAtomicPortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredAtomicPortableSelfTest.java
index 8996355..80353c7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredAtomicPortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredAtomicPortableSelfTest.java
@@ -21,7 +21,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheOffHeapTieredAtomicSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionAtomicPortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionAtomicPortableSelfTest.java
index 1eb5d1a..a8c87ea 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionAtomicPortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionAtomicPortableSelfTest.java
@@ -21,7 +21,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheOffHeapTieredEvictionAtomicSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObject;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionPortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionPortableSelfTest.java
index 85f0298..0665f20 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionPortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredEvictionPortableSelfTest.java
@@ -21,7 +21,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheOffHeapTieredEvictionSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.binary.BinaryObject;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredPortableSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredPortableSelfTest.java
index 22c9a70..8ab7f42 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredPortableSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCacheOffHeapTieredPortableSelfTest.java
@@ -21,7 +21,7 @@
 import org.apache.ignite.configuration.BinaryConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.GridCacheOffHeapTieredSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesNearPartitionedByteArrayValuesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesNearPartitionedByteArrayValuesSelfTest.java
index 8e4bb35..ce3a9e1 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesNearPartitionedByteArrayValuesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesNearPartitionedByteArrayValuesSelfTest.java
@@ -18,7 +18,7 @@
 
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridCacheAbstractNearPartitionedByteArrayValuesSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesPartitionedOnlyByteArrayValuesSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesPartitionedOnlyByteArrayValuesSelfTest.java
index 256e0c2..e20166e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesPartitionedOnlyByteArrayValuesSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/portable/distributed/dht/GridCachePortablesPartitionedOnlyByteArrayValuesSelfTest.java
@@ -19,7 +19,7 @@
 
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheAbstractPartitionedOnlyByteArrayValuesSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 
 /**
  *
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeBinarizableArgTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeBinarizableArgTask.java
index 8eba80b..148d828 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeBinarizableArgTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeBinarizableArgTask.java
@@ -19,14 +19,14 @@
 
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteException;
+import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.compute.ComputeJob;
 import org.apache.ignite.compute.ComputeJobAdapter;
 import org.apache.ignite.compute.ComputeJobResult;
 import org.apache.ignite.compute.ComputeTaskAdapter;
+import org.apache.ignite.internal.portable.BinaryObjectEx;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.binary.BinaryType;
-import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.resources.IgniteInstanceResource;
 import org.jetbrains.annotations.Nullable;
 
@@ -87,9 +87,9 @@
 
         /** {@inheritDoc} */
         @Nullable @Override public Object execute() {
-            BinaryObject arg0 = ((BinaryObject)arg);
+            BinaryObjectEx arg0 = ((BinaryObjectEx)arg);
 
-            BinaryType meta = ignite.binary().metadata(arg0.typeId());
+            BinaryType meta = ignite.binary().type(arg0.typeId());
 
             if (meta == null)
                 throw new IgniteException("Metadata doesn't exist.");
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java
index c464945..a284883 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformComputeEchoTask.java
@@ -194,9 +194,9 @@
                 case TYPE_ENUM_FIELD:
                     IgniteCache<Integer, BinaryObject> cache = ignite.cache(null).withKeepBinary();
                     BinaryObject obj = cache.get(TYPE_ENUM_FIELD);
-                    PlatformComputeEnum val = obj.field("interopEnum");
+                    BinaryObject val = obj.field("interopEnum");
 
-                    return val;
+                    return val.deserialize();
 
                 default:
                     throw new IgniteException("Unknown type: " + type);
diff --git a/modules/core/src/test/java/org/apache/ignite/session/GridSessionCheckpointSelfTest.java b/modules/core/src/test/java/org/apache/ignite/session/GridSessionCheckpointSelfTest.java
index 07e558c..2fd62c1 100644
--- a/modules/core/src/test/java/org/apache/ignite/session/GridSessionCheckpointSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/session/GridSessionCheckpointSelfTest.java
@@ -19,6 +19,12 @@
 
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.portable.BinaryCachingMetadataHandler;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.PortableContext;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.MarshallerContextTestImpl;
 import org.apache.ignite.spi.checkpoint.cache.CacheCheckpointSpi;
 import org.apache.ignite.spi.checkpoint.jdbc.JdbcCheckpointSpi;
 import org.apache.ignite.spi.checkpoint.sharedfs.SharedFsCheckpointSpi;
@@ -89,6 +95,16 @@
 
         cfg.setCheckpointSpi(spi);
 
+        if (cfg.getMarshaller() instanceof BinaryMarshaller) {
+            PortableContext ctx = new PortableContext(BinaryCachingMetadataHandler.create(), cfg);
+
+            Marshaller marsh = cfg.getMarshaller();
+
+            marsh.setContext(new MarshallerContextTestImpl(null));
+
+            IgniteUtils.invoke(BinaryMarshaller.class, marsh, "setPortableContext", ctx, cfg);
+        }
+
         GridSessionCheckpointSelfTest.spi = spi;
 
         checkCheckpoints(cfg);
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteCacheSslStartStopSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteCacheSslStartStopSelfTest.java
index 3324fcc..12bd020 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteCacheSslStartStopSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteCacheSslStartStopSelfTest.java
@@ -32,6 +32,7 @@
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
+        fail("https://issues.apache.org/jira/browse/IGNITE-1924");
         cfg.setSslContextFactory(GridTestUtils.sslFactory());
 
         return cfg;
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
index d1c3d9f..7116227 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
@@ -42,10 +42,15 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Queue;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
+import java.util.UUID;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import javax.cache.CacheException;
 import javax.cache.configuration.Factory;
@@ -81,6 +86,7 @@
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.internal.util.lang.GridAbsClosure;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
+import org.apache.ignite.internal.util.lang.IgnitePair;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.internal.util.typedef.T2;
@@ -88,6 +94,7 @@
 import org.apache.ignite.internal.util.typedef.internal.LT;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.spi.swapspace.inmemory.GridTestSwapSpaceSpi;
 import org.apache.ignite.ssl.SslContextFactory;
 import org.apache.ignite.testframework.config.GridTestProperties;
@@ -147,6 +154,9 @@
     /** */
     private static final GridBusyLock busyLock = new GridBusyLock();
 
+    /** */
+    public static final ConcurrentMap<IgnitePair<UUID>, IgnitePair<Queue<Message>>> msgMap = new ConcurrentHashMap<>();
+
     /**
      * Ensure singleton.
      */
@@ -155,6 +165,55 @@
     }
 
     /**
+     * @param from From node ID.
+     * @param to To node ID.
+     * @param msg Message.
+     * @param sent Sent or received.
+     */
+    public static void addMessage(UUID from, UUID to, Message msg, boolean sent) {
+        IgnitePair<UUID> key = F.pair(from, to);
+
+        IgnitePair<Queue<Message>> val = msgMap.get(key);
+
+        if (val == null) {
+            IgnitePair<Queue<Message>> old = msgMap.putIfAbsent(key,
+                val = F.<Queue<Message>>pair(new ConcurrentLinkedQueue<Message>(), new ConcurrentLinkedQueue<Message>()));
+
+            if (old != null)
+                val = old;
+        }
+
+        (sent ? val.get1() : val.get2()).add(msg);
+    }
+
+    /**
+     * Dumps all messages tracked with {@link #addMessage(UUID, UUID, Message, boolean)} to std out.
+     */
+    public static void dumpMessages() {
+        for (Map.Entry<IgnitePair<UUID>, IgnitePair<Queue<Message>>> entry : msgMap.entrySet()) {
+            U.debug("\n" + entry.getKey().get1() + " [sent to] " + entry.getKey().get2());
+
+            for (Message message : entry.getValue().get1())
+                U.debug("\t" + message);
+
+            U.debug(entry.getKey().get2() + " [received from] " + entry.getKey().get1());
+
+            for (Message message : entry.getValue().get2())
+                U.debug("\t" + message);
+        }
+    }
+
+//    static {
+//        new Thread(new Runnable() {
+//            @Override public void run() {
+//                JOptionPane.showMessageDialog(null, "Close this to dump messages.");
+//
+//                dumpMessages();
+//            }
+//        }).start();
+//    }
+
+    /**
      * Checks whether callable throws expected exception or not.
      *
      * @param log Logger (optional).
@@ -1728,4 +1787,4 @@
         /** Evict to offheap with eviction policy + evict from offheap to swap when max offheap memory limit is reached. */
         OFFHEAP_EVICT_SWAP,
     }
-}
\ No newline at end of file
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java
index 27a7051..7f27f36 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java
@@ -42,12 +42,18 @@
 import org.apache.ignite.IgniteServices;
 import org.apache.ignite.IgniteSet;
 import org.apache.ignite.IgniteTransactions;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryObjectException;
 import org.apache.ignite.cache.affinity.Affinity;
 import org.apache.ignite.cluster.ClusterGroup;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.CollectionConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.internal.portable.BinaryCachingMetadataHandler;
+import org.apache.ignite.internal.portable.PortableContext;
+import org.apache.ignite.internal.portable.builder.BinaryObjectBuilderImpl;
+import org.apache.ignite.internal.processors.cacheobject.NoOpBinary;
 import org.apache.ignite.lang.IgniteProductVersion;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.plugin.IgnitePlugin;
@@ -79,6 +85,12 @@
     /** */
     private IgniteConfiguration staticCfg;
 
+    /** */
+    private IgniteBinary binaryMock;
+
+    /** */
+    private PortableContext ctx;
+
     /**
      * Mock values
      *
@@ -278,12 +290,37 @@
 
     /** {@inheritDoc} */
     @Override public IgniteBinary binary() {
-        return null;
+        if (binaryMock != null)
+            return binaryMock;
+
+        if (ctx == null) {
+            /** {@inheritDoc} */
+            ctx = new PortableContext(BinaryCachingMetadataHandler.create(), configuration()) {
+                @Override public int typeId(String typeName) {
+                    return typeName.hashCode();
+                }
+            };
+        }
+
+        binaryMock = new NoOpBinary() {
+            /** {@inheritDoc} */
+            @Override public int typeId(String typeName) {
+                return typeName.hashCode();
+            }
+
+            /** {@inheritDoc} */
+            @Override public BinaryObjectBuilder builder(String typeName) throws BinaryObjectException {
+                return new BinaryObjectBuilderImpl(ctx, typeName);
+            }
+        };
+
+        return binaryMock;
     }
 
     /** {@inheritDoc} */
     @Override public void close() {}
 
+    /** {@inheritDoc} */
     @Nullable @Override public IgniteAtomicSequence atomicSequence(String name, long initVal, boolean create) {
         return null;
     }
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java
index 406318f..970002d 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteTestResources.java
@@ -26,7 +26,12 @@
 import javax.management.MBeanServer;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.portable.BinaryCachingMetadataHandler;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.PortableContext;
 import org.apache.ignite.internal.processors.resource.GridResourceProcessor;
+import org.apache.ignite.internal.util.IgniteUtils;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.marshaller.MarshallerContextTestImpl;
@@ -258,6 +263,12 @@
 
         marsh.setContext(new MarshallerContextTestImpl());
 
+        if (marsh instanceof BinaryMarshaller) {
+            PortableContext ctx = new PortableContext(BinaryCachingMetadataHandler.create(), new IgniteConfiguration());
+
+            IgniteUtils.invoke(BinaryMarshaller.class, marsh, "setPortableContext", ctx, new IgniteConfiguration());
+        }
+
         return marsh;
     }
 }
\ No newline at end of file
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
index d2e17d8..035f1b0 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
@@ -196,11 +196,21 @@
     }
 
     /** {@inheritDoc} */
+    @Override public long sizeLong(CachePeekMode... peekModes) throws CacheException {
+        return compute.call(new SizeLongTask(cacheName, isAsync, peekModes, false));
+    }
+
+    /** {@inheritDoc} */
     @Override public int localSize(CachePeekMode... peekModes) {
         return compute.call(new SizeTask(cacheName, isAsync, peekModes, true));
     }
 
     /** {@inheritDoc} */
+    @Override public long localSizeLong(CachePeekMode... peekModes) {
+        return compute.call(new SizeLongTask(cacheName, isAsync, peekModes, true));
+    }
+
+    /** {@inheritDoc} */
     @Override  public <T> Map<K, EntryProcessorResult<T>> invokeAll(
         Map<? extends K, ? extends EntryProcessor<K, V, T>> map,
         Object... args)
@@ -649,6 +659,34 @@
     /**
      *
      */
+    private static class SizeLongTask extends CacheTaskAdapter<Void, Void, Long> {
+        /** Peek modes. */
+        private final CachePeekMode[] peekModes;
+
+        /** Local. */
+        private final boolean loc;
+
+        /**
+         * @param cacheName Cache name.
+         * @param async Async.
+         * @param peekModes Peek modes.
+         * @param loc Local.
+         */
+        public SizeLongTask(String cacheName, boolean async, CachePeekMode[] peekModes, boolean loc) {
+            super(cacheName, async);
+            this.loc = loc;
+            this.peekModes = peekModes;
+        }
+
+        /** {@inheritDoc} */
+        @Override public Long call() throws Exception {
+            return loc ? cache().localSizeLong(peekModes) : cache().sizeLong(peekModes);
+        }
+    }
+
+    /**
+     *
+     */
     private static class GetTask<K, V> extends CacheTaskAdapter<K, V, V> {
         /** Key. */
         private final K key;
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheDataStructuresSelfTestSuite.java
similarity index 61%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheDataStructuresSelfTestSuite.java
index 6548210..1a77518 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheDataStructuresSelfTestSuite.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class IgniteBinaryObjectsCacheDataStructuresSelfTestSuite {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+        return IgniteCacheDataStructuresSelfTestSuite.suite();
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheExpiryPolicyTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheExpiryPolicyTestSuite.java
new file mode 100644
index 0000000..b5bd4de
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheExpiryPolicyTestSuite.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.internal.processors.cache.expiry.IgniteCacheExpiryPolicyTestSuite;
+import org.apache.ignite.testframework.config.GridTestProperties;
+
+/**
+ *
+ */
+public class IgniteBinaryObjectsCacheExpiryPolicyTestSuite {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
+
+        return IgniteCacheExpiryPolicyTestSuite.suite();
+    }
+}
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheRestartTestSuite.java
similarity index 62%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheRestartTestSuite.java
index 6548210..0ef9446 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheRestartTestSuite.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class IgniteBinaryObjectsCacheRestartTestSuite {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+        return IgniteCacheRestartTestSuite.suite();
+    }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite2.java
similarity index 62%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite2.java
index 6548210..e8064e7 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite2.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class IgniteBinaryObjectsCacheTestSuite2 {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+        return IgniteCacheTestSuite2.suite();
+    }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java
similarity index 62%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java
index 6548210..736a862 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite3.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class IgniteBinaryObjectsCacheTestSuite3 {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+        return IgniteCacheTestSuite3.suite();
+    }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite4.java
similarity index 62%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite4.java
index 6548210..4f88e0a 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsCacheTestSuite4.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class IgniteBinaryObjectsCacheTestSuite4 {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+        return IgniteCacheTestSuite4.suite();
+    }
 }
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsComputeGridTestSuite.java
similarity index 62%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsComputeGridTestSuite.java
index 6548210..878f59f 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsComputeGridTestSuite.java
@@ -15,18 +15,19 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
+import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
+public class IgniteBinaryObjectsComputeGridTestSuite {
+    public static TestSuite suite() throws Exception {
+        GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName());
 
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+        return IgniteComputeGridTestSuite.suite();
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuite3.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuite3.java
index 1f94f9e..4b04c05 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuite3.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuite3.java
@@ -21,8 +21,6 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteCachePutRetryAtomicSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.IgniteCachePutRetryTransactionalSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.atomic.IgniteCachePutRetryAtomicPrimaryWriteOrderSelfTest;
-import org.apache.ignite.internal.util.IgniteUtils;
-import org.apache.ignite.spi.communication.tcp.IgniteCacheSslStartStopSelfTest;
 
 /**
  * Test suite.
@@ -39,10 +37,6 @@
         suite.addTestSuite(IgniteCachePutRetryAtomicPrimaryWriteOrderSelfTest.class);
         suite.addTestSuite(IgniteCachePutRetryTransactionalSelfTest.class);
 
-        // Disable SSL test with old JDK because of https://bugs.openjdk.java.net/browse/JDK-8013809.
-        if (!IgniteUtils.isHotSpot() || IgniteUtils.isJavaVersionAtLeast("1.7.0_65"))
-            suite.addTestSuite(IgniteCacheSslStartStopSelfTest.class);
-
         return suite;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuiteSsl.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuiteSsl.java
new file mode 100644
index 0000000..99a1463
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheFailoverTestSuiteSsl.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.ignite.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.spi.communication.tcp.IgniteCacheSslStartStopSelfTest;
+
+/**
+ * Test suite.
+ */
+public class IgniteCacheFailoverTestSuiteSsl extends TestSuite {
+    /**
+     * @return Ignite Cache Failover test suite.
+     * @throws Exception Thrown in case of the failure.
+     */
+    public static TestSuite suite() throws Exception {
+        TestSuite suite = new TestSuite("Cache Failover Test Suite SSL");
+
+        // Disable SSL test with old JDK because of https://bugs.openjdk.java.net/browse/JDK-8013809.
+        if (!IgniteUtils.isHotSpot() || IgniteUtils.isJavaVersionAtLeast("1.7.0_65"))
+            suite.addTestSuite(IgniteCacheSslStartStopSelfTest.class);
+
+        return suite;
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java
index 8af9443..ca31c28 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite.java
@@ -32,11 +32,13 @@
 import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreMultitreadedSelfTest;
 import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreOptimizedMarshallerSelfTest;
 import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreTest;
-import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStorePortableMarshallerSelfTest;
+import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreBinaryMarshallerSelfTest;
 import org.apache.ignite.cache.store.jdbc.GridCacheJdbcBlobStoreMultithreadedSelfTest;
 import org.apache.ignite.cache.store.jdbc.GridCacheJdbcBlobStoreSelfTest;
 import org.apache.ignite.internal.processors.cache.CacheAffinityCallSelfTest;
+import org.apache.ignite.internal.processors.cache.CacheDeferredDeleteSanitySelfTest;
 import org.apache.ignite.internal.processors.cache.CacheFutureExceptionSelfTest;
+import org.apache.ignite.internal.processors.cache.CachePutEventListenerErrorSelfTest;
 import org.apache.ignite.internal.processors.cache.CacheNamesSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheAffinityApiSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheAffinityMapperSelfTest;
@@ -214,7 +216,7 @@
         suite.addTestSuite(GridCacheJdbcBlobStoreMultithreadedSelfTest.class);
         suite.addTestSuite(CacheJdbcPojoStoreTest.class);
         suite.addTestSuite(CacheJdbcPojoStoreOptimizedMarshallerSelfTest.class);
-        suite.addTestSuite(CacheJdbcPojoStorePortableMarshallerSelfTest.class);
+        suite.addTestSuite(CacheJdbcPojoStoreBinaryMarshallerSelfTest.class);
         suite.addTestSuite(CacheJdbcPojoStoreMultitreadedSelfTest.class);
         suite.addTestSuite(GridCacheBalancingStoreSelfTest.class);
         suite.addTestSuite(GridCacheAffinityApiSelfTest.class);
@@ -262,6 +264,7 @@
         suite.addTestSuite(GridCachePartitionedOffHeapLocalStoreSelfTest.class);
         suite.addTestSuite(GridCacheTxPartitionedLocalStoreSelfTest.class);
         suite.addTestSuite(IgniteCacheSystemTransactionsSelfTest.class);
+        suite.addTestSuite(CacheDeferredDeleteSanitySelfTest.class);
 
         suite.addTest(IgniteCacheTcpClientDiscoveryTestSuite.suite());
 
@@ -274,6 +277,8 @@
 
         suite.addTestSuite(IgniteCacheNearLockValueSelfTest.class);
 
+        suite.addTestSuite(CachePutEventListenerErrorSelfTest.class);
+
         return suite;
     }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
index 5138dac..74b688f 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
@@ -53,7 +53,6 @@
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtEvictionSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtEvictionsDisabledSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtExpiredEntriesPreloadSelfTest;
-import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtInternalEntrySelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtMappingSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtPreloadBigDataSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDhtPreloadDelayedSelfTest;
@@ -188,7 +187,6 @@
         suite.addTest(new TestSuite(GridCachePartitionedTxTimeoutSelfTest.class));
         suite.addTest(new TestSuite(GridCacheFinishPartitionsSelfTest.class));
         suite.addTest(new TestSuite(GridCacheDhtEntrySelfTest.class));
-        suite.addTest(new TestSuite(GridCacheDhtInternalEntrySelfTest.class));
         suite.addTest(new TestSuite(GridCacheDhtMappingSelfTest.class));
         suite.addTest(new TestSuite(GridCachePartitionedTxMultiThreadedSelfTest.class));
         suite.addTest(new TestSuite(GridCachePartitionedNearDisabledTxMultiThreadedSelfTest.class));
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheFullApiTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheFullApiTestSuite.java
index 5c5bb5a..f0f5fcc 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheFullApiTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheFullApiTestSuite.java
@@ -18,7 +18,7 @@
 package org.apache.ignite.testsuites;
 
 import junit.framework.TestSuite;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheTestSuite.java
index 09a0adb..6e34a98 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheTestSuite.java
@@ -44,7 +44,7 @@
 import org.apache.ignite.internal.processors.cache.portable.distributed.dht.GridCachePortablesNearPartitionedByteArrayValuesSelfTest;
 import org.apache.ignite.internal.processors.cache.portable.distributed.dht.GridCachePortablesPartitionedOnlyByteArrayValuesSelfTest;
 import org.apache.ignite.internal.processors.datastreamer.DataStreamProcessorSelfTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.testframework.config.GridTestProperties;
 
 /**
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableObjectsTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableObjectsTestSuite.java
index 16eeb2b..62952b5 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableObjectsTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgnitePortableObjectsTestSuite.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.testsuites;
 
 import junit.framework.TestSuite;
+import org.apache.ignite.internal.portable.BinaryEnumsSelfTest;
 import org.apache.ignite.internal.portable.GridPortableAffinityKeySelfTest;
 import org.apache.ignite.internal.portable.BinaryObjectBuilderAdditionalSelfTest;
 import org.apache.ignite.internal.portable.BinaryObjectBuilderSelfTest;
@@ -36,6 +37,7 @@
 import org.apache.ignite.internal.portable.noncompact.BinaryMarshallerNonCompactSelfTest;
 import org.apache.ignite.internal.portable.noncompact.BinaryObjectBuilderAdditionalNonCompactSelfTest;
 import org.apache.ignite.internal.portable.noncompact.BinaryObjectBuilderNonCompactSelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteBinaryMetadataUpdateChangingTopologySelfTest;
 import org.apache.ignite.internal.processors.cache.portable.GridCacheClientNodeBinaryObjectMetadataMultinodeTest;
 import org.apache.ignite.internal.processors.cache.portable.GridCacheClientNodeBinaryObjectMetadataTest;
 import org.apache.ignite.internal.processors.cache.portable.GridCachePortableStoreObjectsSelfTest;
@@ -72,6 +74,7 @@
         suite.addTestSuite(BinaryFieldsOffheapSelfTest.class);
         suite.addTestSuite(BinaryFooterOffsetsHeapSelfTest.class);
         suite.addTestSuite(BinaryFooterOffsetsOffheapSelfTest.class);
+        suite.addTestSuite(BinaryEnumsSelfTest.class);
         suite.addTestSuite(GridPortableMetaDataSelfTest.class);
         suite.addTestSuite(GridPortableAffinityKeySelfTest.class);
         suite.addTestSuite(GridPortableWildcardsSelfTest.class);
@@ -104,6 +107,7 @@
 
         suite.addTestSuite(GridCacheClientNodeBinaryObjectMetadataTest.class);
         suite.addTestSuite(GridCacheClientNodeBinaryObjectMetadataMultinodeTest.class);
+        suite.addTestSuite(IgniteBinaryMetadataUpdateChangingTopologySelfTest.class);
 
         return suite;
     }
diff --git a/modules/flume/README.txt b/modules/flume/README.txt
index 5b574e3..bf7e0ff 100644
--- a/modules/flume/README.txt
+++ b/modules/flume/README.txt
@@ -1,42 +1,18 @@
-Apache Ignite Flume Streamer Module
-------------------------
+Apache Ignite Flume Sink Module
+-------------------------------
 
-Apache Ignite Flume Streamer module provides streaming from Flume to Ignite cache.
+IgniteSink is a Flume sink that extracts Events from an associated Flume channel and injects into an Ignite cache.
+Flume 1.6.0 is supported.
 
-To enable Flume Streamer module when starting a standalone node, move 'optional/ignite-Flume' folder to
-'libs' folder before running 'ignite.{sh|bat}' script. The content of the module folder will
-be added to classpath in this case.
-
-Importing Ignite Flume Streamer Module In Maven Project
--------------------------------------
-
-If you are using Maven to manage dependencies of your project, you can add JCL module
-dependency like this (replace '${ignite.version}' with actual Ignite version you are
-interested in):
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
-                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    ...
-    <dependencies>
-        ...
-        <dependency>
-            <groupId>org.apache.ignite</groupId>
-            <artifactId>ignite-Flume</artifactId>
-            <version>${ignite.version}</version>
-        </dependency>
-        ...
-    </dependencies>
-    ...
-</project>
-
+IgniteSink, which can be found in 'optional/ignite-flume', and its dependencies have to be included in the agent's classpath,
+as described in the following subsection, before starting the Flume agent.
 
 ## Setting up and running
 
 1. Create a transformer by implementing EventTransformer interface.
-2. Build it and copy to ${FLUME_HOME}/plugins.d/ignite-sink/lib.
-3. Copy other Ignite-related jar files to ${FLUME_HOME}/plugins.d/ignite-sink/libext to have them as shown below.
+2. Create 'ignite' directory inside plugins.d directory which is located in ${FLUME_HOME}. If the plugins.d directory is not there, create it.
+3. Build it and copy to ${FLUME_HOME}/plugins.d/ignite-sink/lib.
+4. Copy other Ignite-related jar files from Apache Ignite distribution to ${FLUME_HOME}/plugins.d/ignite-sink/libext to have them as shown below.
 
 ```
 plugins.d/
@@ -46,7 +22,7 @@
     `-- libext
         |-- cache-api-1.0.0.jar
         |-- ignite-core-x.x.x.jar
-        |-- ignite-flume-x.x.x.jar
+        |-- ignite-flume-x.x.x.jar <-- IgniteSink
         |-- ignite-spring-x.x.x.jar
         |-- spring-aop-4.1.0.RELEASE.jar
         |-- spring-beans-4.1.0.RELEASE.jar
diff --git a/modules/flume/src/main/java/org/apache/ignite/stream/flume/package-info.java b/modules/flume/src/main/java/org/apache/ignite/stream/flume/package-info.java
new file mode 100644
index 0000000..a88e39e
--- /dev/null
+++ b/modules/flume/src/main/java/org/apache/ignite/stream/flume/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Flume Sink.
+ */
+package org.apache.ignite.stream.flume;
\ No newline at end of file
diff --git a/modules/flume/src/test/java/org/apache/ignite/stream/flume/package-info.java b/modules/flume/src/test/java/org/apache/ignite/stream/flume/package-info.java
new file mode 100644
index 0000000..a88e39e
--- /dev/null
+++ b/modules/flume/src/test/java/org/apache/ignite/stream/flume/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Flume Sink.
+ */
+package org.apache.ignite.stream.flume;
\ No newline at end of file
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/GridH2ResultSetIterator.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/GridH2ResultSetIterator.java
index 2c67638..3603bb5 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/GridH2ResultSetIterator.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/GridH2ResultSetIterator.java
@@ -41,14 +41,19 @@
     protected final Object[] row;
 
     /** */
+    private final boolean closeStmt;
+
+    /** */
     private boolean hasRow;
 
     /**
      * @param data Data array.
+     * @param closeStmt If {@code true} closes result set statement when iterator is closed.
      * @throws IgniteCheckedException If failed.
      */
-    protected GridH2ResultSetIterator(ResultSet data) throws IgniteCheckedException {
+    protected GridH2ResultSetIterator(ResultSet data, boolean closeStmt) throws IgniteCheckedException {
         this.data = data;
+        this.closeStmt = closeStmt;
 
         if (data != null) {
             try {
@@ -115,11 +120,13 @@
             // Nothing to close.
             return;
 
-        try {
-            U.closeQuiet(data.getStatement());
-        }
-        catch (SQLException e) {
-            throw new IgniteCheckedException(e);
+        if (closeStmt) {
+            try {
+                U.closeQuiet(data.getStatement());
+            }
+            catch (SQLException e) {
+                throw new IgniteCheckedException(e);
+            }
         }
 
         U.closeQuiet(data);
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
index d5efebf..1437a16 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
@@ -49,6 +49,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import javax.cache.Cache;
 import javax.cache.CacheException;
@@ -79,6 +80,7 @@
 import org.apache.ignite.internal.processors.query.GridQueryFieldsResultAdapter;
 import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
 import org.apache.ignite.internal.processors.query.GridQueryIndexing;
+import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2KeyValueRowOffheap;
@@ -93,12 +95,14 @@
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQuerySplitter;
 import org.apache.ignite.internal.processors.query.h2.twostep.GridMapQueryExecutor;
 import org.apache.ignite.internal.processors.query.h2.twostep.GridReduceQueryExecutor;
+import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap;
 import org.apache.ignite.internal.util.GridEmptyCloseableIterator;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
 import org.apache.ignite.internal.util.lang.GridCloseableIterator;
 import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeGuard;
 import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T3;
 import org.apache.ignite.internal.util.typedef.internal.LT;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.SB;
@@ -176,6 +180,12 @@
         ";DEFAULT_LOCK_TIMEOUT=10000;FUNCTIONS_IN_SCHEMA=true;OPTIMIZE_REUSE_RESULTS=0;QUERY_CACHE_SIZE=0;" +
         "RECOMPILE_ALWAYS=1;MAX_OPERATION_MEMORY=0";
 
+    /** */
+    private static final int PREPARED_STMT_CACHE_SIZE = 256;
+
+    /** */
+    private static final int TWO_STEP_QRY_CACHE_SIZE = 1024;
+
     /** Field name for key. */
     public static final String KEY_FIELD_NAME = "_key";
 
@@ -190,6 +200,8 @@
      */
     static {
         try {
+            System.setProperty("h2.objectCache", "false");
+
             COMMAND_FIELD = JdbcPreparedStatement.class.getDeclaredField("command");
 
             COMMAND_FIELD.setAccessible(true);
@@ -242,6 +254,9 @@
                 c = initialValue();
 
                 set(c);
+
+                // Reset statement cache when new connection is created.
+                stmtCache.remove(Thread.currentThread());
             }
 
             return c;
@@ -266,6 +281,13 @@
     /** */
     private volatile GridKernalContext ctx;
 
+    /** Statement cache. */
+    private final ConcurrentHashMap<Thread, StatementCache> stmtCache = new ConcurrentHashMap<>();
+
+    /** */
+    private final GridBoundedConcurrentLinkedHashMap<T3<String, String, Boolean>, TwoStepCachedQuery> twoStepCache =
+        new GridBoundedConcurrentLinkedHashMap<>(TWO_STEP_QRY_CACHE_SIZE);
+
     /**
      * @param space Space.
      * @return Connection.
@@ -280,6 +302,46 @@
     }
 
     /**
+     * @param c Connection.
+     * @param sql SQL.
+     * @param useStmtCache If {@code true} uses statement cache.
+     * @return Prepared statement.
+     * @throws SQLException If failed.
+     */
+    private PreparedStatement prepareStatement(Connection c, String sql, boolean useStmtCache) throws SQLException {
+        if (useStmtCache) {
+            Thread curThread = Thread.currentThread();
+
+            StatementCache cache = stmtCache.get(curThread);
+
+            if (cache == null) {
+                StatementCache cache0 = new StatementCache(PREPARED_STMT_CACHE_SIZE);
+
+                cache = stmtCache.putIfAbsent(curThread, cache0);
+
+                if (cache == null)
+                    cache = cache0;
+            }
+
+            PreparedStatement stmt = cache.get(sql);
+
+            if (stmt != null && !stmt.isClosed()) {
+                assert stmt.getConnection() == c;
+
+                return stmt;
+            }
+
+            stmt = c.prepareStatement(sql);
+
+            cache.put(sql, stmt);
+
+            return stmt;
+        }
+        else
+            return c.prepareStatement(sql);
+    }
+
+    /**
      * Gets DB connection.
      *
      * @param schema Whether to set schema for connection or not.
@@ -648,7 +710,7 @@
         try {
             Connection conn = connectionForThread(schema(spaceName));
 
-            ResultSet rs = executeSqlQueryWithTimer(spaceName, conn, qry, params);
+            ResultSet rs = executeSqlQueryWithTimer(spaceName, conn, qry, params, true);
 
             List<GridQueryFieldMetadata> meta = null;
 
@@ -710,15 +772,16 @@
      * @param conn Connection,.
      * @param sql Sql query.
      * @param params Parameters.
+     * @param useStmtCache If {@code true} uses statement cache.
      * @return Result.
      * @throws IgniteCheckedException If failed.
      */
-    private ResultSet executeSqlQuery(Connection conn, String sql, Collection<Object> params)
+    private ResultSet executeSqlQuery(Connection conn, String sql, Collection<Object> params, boolean useStmtCache)
         throws IgniteCheckedException {
         PreparedStatement stmt;
 
         try {
-            stmt = conn.prepareStatement(sql);
+            stmt = prepareStatement(conn, sql, useStmtCache);
         }
         catch (SQLException e) {
             throw new IgniteCheckedException("Failed to parse SQL query: " + sql, e);
@@ -747,18 +810,23 @@
     /**
      * Executes sql query and prints warning if query is too slow..
      *
+     * @param space Space name.
      * @param conn Connection,.
      * @param sql Sql query.
      * @param params Parameters.
+     * @param useStmtCache If {@code true} uses statement cache.
      * @return Result.
      * @throws IgniteCheckedException If failed.
      */
-    public ResultSet executeSqlQueryWithTimer(String space, Connection conn, String sql,
-        @Nullable Collection<Object> params) throws IgniteCheckedException {
+    public ResultSet executeSqlQueryWithTimer(String space,
+        Connection conn,
+        String sql,
+        @Nullable Collection<Object> params,
+        boolean useStmtCache) throws IgniteCheckedException {
         long start = U.currentTimeMillis();
 
         try {
-            ResultSet rs = executeSqlQuery(conn, sql, params);
+            ResultSet rs = executeSqlQuery(conn, sql, params, useStmtCache);
 
             long time = U.currentTimeMillis() - start;
 
@@ -767,7 +835,7 @@
             if (time > longQryExecTimeout) {
                 String msg = "Query execution is too long (" + time + " ms): " + sql;
 
-                ResultSet plan = executeSqlQuery(conn, "EXPLAIN " + sql, params);
+                ResultSet plan = executeSqlQuery(conn, "EXPLAIN " + sql, params, false);
 
                 plan.next();
 
@@ -803,7 +871,7 @@
 
         String sql = generateQuery(qry, tbl);
 
-        return executeSqlQueryWithTimer(space, conn, sql, params);
+        return executeSqlQueryWithTimer(space, conn, sql, params, true);
     }
 
     /**
@@ -924,41 +992,52 @@
 
     /** {@inheritDoc} */
     @Override public QueryCursor<List<?>> queryTwoStep(GridCacheContext<?,?> cctx, SqlFieldsQuery qry) {
-        String space = cctx.name();
-        String sqlQry = qry.getSql();
+        final String space = cctx.name();
+        final String sqlQry = qry.getSql();
 
         Connection c = connectionForSpace(space);
 
-        PreparedStatement stmt;
-
-        try {
-            stmt = c.prepareStatement(sqlQry);
-        }
-        catch (SQLException e) {
-            throw new CacheException("Failed to parse query: " + sqlQry, e);
-        }
-
-        try {
-            bindParameters(stmt, F.asList(qry.getArgs()));
-        }
-        catch (IgniteCheckedException e) {
-            throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" +
-                Arrays.deepToString(qry.getArgs()) + "]", e);
-        }
-
         GridCacheTwoStepQuery twoStepQry;
         List<GridQueryFieldMetadata> meta;
 
-        try {
-            twoStepQry = GridSqlQuerySplitter.split((JdbcPreparedStatement)stmt, qry.getArgs(), qry.isCollocated());
+        final T3<String, String, Boolean> cachedQryKey = new T3<>(space, sqlQry, qry.isCollocated());
+        TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey);
 
-            meta = meta(stmt.getMetaData());
+        if (cachedQry != null) {
+            twoStepQry = cachedQry.twoStepQry.copy(qry.getArgs());
+            meta = cachedQry.meta;
         }
-        catch (SQLException e) {
-            throw new CacheException(e);
-        }
-        finally {
-            U.close(stmt, log);
+        else {
+            PreparedStatement stmt;
+
+            try {
+                // Do not cache this statement because the whole two step query object will be cached later on.
+                stmt = prepareStatement(c, sqlQry, false);
+            }
+            catch (SQLException e) {
+                throw new CacheException("Failed to parse query: " + sqlQry, e);
+            }
+            try {
+                try {
+                    bindParameters(stmt, F.asList(qry.getArgs()));
+                }
+                catch (IgniteCheckedException e) {
+                    throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" +
+                        Arrays.deepToString(qry.getArgs()) + "]", e);
+                }
+
+                try {
+                    twoStepQry = GridSqlQuerySplitter.split((JdbcPreparedStatement)stmt, qry.getArgs(), qry.isCollocated());
+
+                    meta = meta(stmt.getMetaData());
+                }
+                catch (SQLException e) {
+                    throw new CacheException(e);
+                }
+            }
+            finally {
+                U.close(stmt, log);
+            }
         }
 
         if (log.isDebugEnabled())
@@ -970,6 +1049,11 @@
 
         cursor.fieldsMeta(meta);
 
+        if (cachedQry == null && !twoStepQry.explain()) {
+            cachedQry = new TwoStepCachedQuery(meta, twoStepQry.copy(null));
+            twoStepCache.putIfAbsent(cachedQryKey, cachedQry);
+        }
+
         return cursor;
     }
 
@@ -1542,6 +1626,31 @@
     }
 
     /**
+     * Cached two-step query.
+     */
+    private static final class TwoStepCachedQuery {
+        /** */
+        final List<GridQueryFieldMetadata> meta;
+
+        /** */
+        final GridCacheTwoStepQuery twoStepQry;
+
+        /**
+         * @param meta Fields metadata.
+         * @param twoStepQry Query.
+         */
+        public TwoStepCachedQuery(List<GridQueryFieldMetadata> meta, GridCacheTwoStepQuery twoStepQry) {
+            this.meta = meta;
+            this.twoStepQry = twoStepQry;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(TwoStepCachedQuery.class, this);
+        }
+    }
+
+    /**
      * Wrapper to store connection and flag is schema set or not.
      */
     private static class ConnectionWrapper {
@@ -1889,7 +1998,7 @@
          * @throws IgniteCheckedException If failed.
          */
         protected FieldsIterator(ResultSet data) throws IgniteCheckedException {
-            super(data);
+            super(data, false);
         }
 
         /** {@inheritDoc} */
@@ -1914,7 +2023,7 @@
          * @throws IgniteCheckedException If failed.
          */
         protected KeyValIterator(ResultSet data) throws IgniteCheckedException {
-            super(data);
+            super(data, false);
         }
 
         /** {@inheritDoc} */
@@ -2091,6 +2200,12 @@
         /** */
         private final boolean preferSwapVal;
 
+        /** */
+        private final boolean snapshotableIdx;
+
+        /** */
+        private final GridQueryProperty[] props;
+
         /**
          * @param type Type descriptor.
          * @param schema Schema.
@@ -2120,7 +2235,18 @@
             keyType = DataType.getTypeFromClass(type.keyClass());
             valType = DataType.getTypeFromClass(type.valueClass());
 
+            props = new GridQueryProperty[fields.length];
+
+            for (int i = 0; i < fields.length; i++) {
+                GridQueryProperty p = type.property(fields[i]);
+
+                assert p != null : fields[i];
+
+                props[i] = p;
+            }
+
             preferSwapVal = schema.ccfg.getMemoryMode() == CacheMemoryMode.OFFHEAP_TIERED;
+            snapshotableIdx = schema.ccfg.isSnapshotableIndex() || schema.offheap != null;
         }
 
         /** {@inheritDoc} */
@@ -2274,7 +2400,7 @@
         /** {@inheritDoc} */
         @Override public Object columnValue(Object key, Object val, int col) {
             try {
-                return type.value(fields[col], key, val);
+                return props[col].value(key, val);
             }
             catch (IgniteCheckedException e) {
                 throw DbException.convert(e);
@@ -2298,5 +2424,40 @@
         @Override public boolean preferSwapValue() {
             return preferSwapVal;
         }
+
+        /** {@inheritDoc} */
+        @Override public boolean snapshotableIndex() {
+            return snapshotableIdx;
+        }
+    }
+
+    /**
+     * Statement cache.
+     */
+    private static class StatementCache extends LinkedHashMap<String, PreparedStatement> {
+        /** */
+        private int size;
+
+        /**
+         * @param size Size.
+         */
+        private StatementCache(int size) {
+            super(size, (float)0.75, true);
+
+            this.size = size;
+        }
+
+        /** {@inheritDoc} */
+        @Override protected boolean removeEldestEntry(Map.Entry<String, PreparedStatement> eldest) {
+            boolean rmv = size() > size;
+
+            if (rmv) {
+                PreparedStatement stmt = eldest.getValue();
+
+                U.closeQuiet(stmt);
+            }
+
+            return rmv;
+        }
     }
 }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
index ed3ff7a..80dcfcb 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
@@ -116,4 +116,9 @@
      * @return {@code True} if should check swap value before offheap.
      */
     public boolean preferSwapValue();
+
+    /**
+     * @return {@code True} if index should support snapshots.
+     */
+    public boolean snapshotableIndex();
 }
\ No newline at end of file
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
index bf318b2..f1e5b16 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
@@ -54,6 +54,7 @@
 import org.h2.value.Value;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
+import org.jsr166.LongAdder8;
 
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.VAL_COL;
 
@@ -79,6 +80,12 @@
     /** */
     private volatile Object[] actualSnapshot;
 
+    /** */
+    private final LongAdder8 size = new LongAdder8();
+
+    /** */
+    private final boolean snapshotEnabled;
+
     /**
      * Creates table.
      *
@@ -101,10 +108,12 @@
         assert idxs != null;
         assert idxs.size() >= 1;
 
-        lock =  new ReentrantReadWriteLock();
+        lock = new ReentrantReadWriteLock();
 
         // Add scan index at 0 which is required by H2.
         idxs.add(0, new ScanIndex(index(0)));
+
+        snapshotEnabled = desc == null || desc.snapshotableIndex();
     }
 
     /** {@inheritDoc} */
@@ -164,7 +173,7 @@
 
         GridUnsafeMemory mem = desc.memory();
 
-        lock.readLock().lock();
+        readLock();
 
         if (mem != null)
             desc.guard().begin();
@@ -183,7 +192,7 @@
             return true;
         }
         finally {
-            lock.readLock().unlock();
+            readUnlock();
 
             if (mem != null)
                 desc.guard().end();
@@ -209,6 +218,9 @@
             }
         }
 
+        if (!snapshotEnabled)
+            return;
+
         Object[] snapshot;
 
         for (long waitTime = 100;; waitTime *= 2) { // Increase wait time to avoid starvation.
@@ -297,16 +309,14 @@
      * Closes table and releases resources.
      */
     public void close() {
-        Lock l = lock.writeLock();
-
-        l.lock();
+        writeLock();
 
         try {
             for (int i = 1, len = idxs.size(); i < len; i++)
                 index(i).close(null);
         }
         finally {
-            l.unlock();
+            writeUnlock();
         }
     }
 
@@ -363,7 +373,7 @@
         // getting updated from different threads with different rows with the same key is impossible.
         GridUnsafeMemory mem = desc == null ? null : desc.memory();
 
-        lock.readLock().lock();
+        readLock();
 
         if (mem != null)
             desc.guard().begin();
@@ -379,6 +389,8 @@
 
                     kvOld.onUnswap(kvOld.getValue(VAL_COL), true);
                 }
+                else if (old == null)
+                    size.increment();
 
                 int len = idxs.size();
 
@@ -414,6 +426,8 @@
                 }
 
                 if (old != null) {
+                    size.decrement();
+
                     // Remove row from all indexes.
                     // Start from 2 because 0 - Scan (don't need to update), 1 - PK (already updated).
                     for (int i = 2, len = idxs.size(); i < len; i++) {
@@ -432,7 +446,7 @@
             return true;
         }
         finally {
-            lock.readLock().unlock();
+            readUnlock();
 
             if (mem != null)
                 desc.guard().end();
@@ -469,6 +483,9 @@
      * Rebuilds all indexes of this table.
      */
     public void rebuildIndexes() {
+        if (!snapshotEnabled)
+            return;
+
         GridUnsafeMemory memory = desc == null ? null : desc.memory();
 
         lock.writeLock().lock();
@@ -579,7 +596,7 @@
 
     /** {@inheritDoc} */
     @Override public long getRowCountApproximation() {
-        return getUniqueIndex().getRowCountApproximation();
+        return size.longValue();
     }
 
     /** {@inheritDoc} */
@@ -605,6 +622,38 @@
     }
 
     /**
+     *
+     */
+    private void readLock() {
+        if (snapshotEnabled)
+            lock.readLock().lock();
+    }
+
+    /**
+     *
+     */
+    private void readUnlock() {
+        if (snapshotEnabled)
+            lock.readLock().unlock();
+    }
+
+    /**
+     *
+     */
+    private void writeLock() {
+        if (snapshotEnabled)
+            lock.writeLock().lock();
+    }
+
+    /**
+     *
+     */
+    private void writeUnlock() {
+        if (snapshotEnabled)
+            lock.writeLock().unlock();
+    }
+
+    /**
      * H2 Table engine.
      */
     @SuppressWarnings({"PublicInnerClass", "FieldAccessedSynchronizedAndUnsynchronized"})
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java
index 387c58b..28adeee 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java
@@ -23,6 +23,7 @@
 import java.util.Iterator;
 import java.util.NavigableMap;
 import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import org.apache.ignite.internal.util.GridEmptyIterator;
 import org.apache.ignite.internal.util.offheap.unsafe.GridOffHeapSnapTreeMap;
 import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeGuard;
@@ -51,8 +52,10 @@
     protected final ConcurrentNavigableMap<GridSearchRowPointer, GridH2Row> tree;
 
     /** */
-    private final ThreadLocal<ConcurrentNavigableMap<GridSearchRowPointer, GridH2Row>> snapshot =
-        new ThreadLocal<>();
+    private final ThreadLocal<ConcurrentNavigableMap<GridSearchRowPointer, GridH2Row>> snapshot = new ThreadLocal<>();
+
+    /** */
+    private final boolean snapshotEnabled;
 
     /**
      * Constructor with index initialization.
@@ -81,40 +84,68 @@
 
         final GridH2RowDescriptor desc = tbl.rowDescriptor();
 
-        tree = desc == null || desc.memory() == null ? new SnapTreeMap<GridSearchRowPointer, GridH2Row>(this) {
-            @Override protected void afterNodeUpdate_nl(Node<GridSearchRowPointer, GridH2Row> node, Object val) {
-                if (val != null)
-                    node.key = (GridSearchRowPointer)val;
+        if (desc == null || desc.memory() == null) {
+            snapshotEnabled = desc == null || desc.snapshotableIndex();
+
+            if (snapshotEnabled) {
+                tree = new SnapTreeMap<GridSearchRowPointer, GridH2Row>(this) {
+                    @Override protected void afterNodeUpdate_nl(Node<GridSearchRowPointer, GridH2Row> node, Object val) {
+                        if (val != null)
+                            node.key = (GridSearchRowPointer)val;
+                    }
+
+                    @Override protected Comparable<? super GridSearchRowPointer> comparable(Object key) {
+                        if (key instanceof ComparableRow)
+                            return (Comparable<? super SearchRow>)key;
+
+                        return super.comparable(key);
+                    }
+                };
             }
+            else {
+                tree = new ConcurrentSkipListMap<>(
+                        new Comparator<GridSearchRowPointer>() {
+                            @Override public int compare(GridSearchRowPointer o1, GridSearchRowPointer o2) {
+                                if (o1 instanceof ComparableRow)
+                                    return ((ComparableRow)o1).compareTo(o2);
 
-            @Override protected Comparable<? super GridSearchRowPointer> comparable(Object key) {
-                if (key instanceof ComparableRow)
-                    return (Comparable<? super SearchRow>)key;
+                                if (o2 instanceof ComparableRow)
+                                    return -((ComparableRow)o2).compareTo(o1);
 
-                return super.comparable(key);
-            }
-        } : new GridOffHeapSnapTreeMap<GridSearchRowPointer, GridH2Row>(desc, desc, desc.memory(), desc.guard(), this) {
-            @Override protected void afterNodeUpdate_nl(long node, GridH2Row val) {
-                final long oldKey = keyPtr(node);
-
-                if (val != null) {
-                    key(node, val);
-
-                    guard.finalizeLater(new Runnable() {
-                        @Override public void run() {
-                            desc.createPointer(oldKey).decrementRefCount();
+                                return compareRows(o1, o2);
+                            }
                         }
-                    });
+                );
+            }
+        }
+        else {
+            assert desc.snapshotableIndex() : desc;
+
+            snapshotEnabled = true;
+
+            tree = new GridOffHeapSnapTreeMap<GridSearchRowPointer, GridH2Row>(desc, desc, desc.memory(), desc.guard(), this) {
+                @Override protected void afterNodeUpdate_nl(long node, GridH2Row val) {
+                    final long oldKey = keyPtr(node);
+
+                    if (val != null) {
+                        key(node, val);
+
+                        guard.finalizeLater(new Runnable() {
+                            @Override public void run() {
+                                desc.createPointer(oldKey).decrementRefCount();
+                            }
+                        });
+                    }
                 }
-            }
 
-            @Override protected Comparable<? super GridSearchRowPointer> comparable(Object key) {
-                if (key instanceof ComparableRow)
-                    return (Comparable<? super SearchRow>)key;
+                @Override protected Comparable<? super GridSearchRowPointer> comparable(Object key) {
+                    if (key instanceof ComparableRow)
+                        return (Comparable<? super SearchRow>)key;
 
-                return super.comparable(key);
-            }
-        };
+                    return super.comparable(key);
+                }
+            };
+        }
     }
 
     /**
@@ -133,6 +164,9 @@
      */
     @SuppressWarnings("unchecked")
     @Override public Object takeSnapshot(@Nullable Object s) {
+        if (!snapshotEnabled)
+            return null;
+
         assert snapshot.get() == null;
 
         if (s == null)
@@ -148,6 +182,9 @@
      * Releases snapshot for current thread.
      */
     @Override public void releaseSnapshot() {
+        if (!snapshotEnabled)
+            return;
+
         ConcurrentNavigableMap<GridSearchRowPointer, GridH2Row> s = snapshot.get();
 
         snapshot.remove();
@@ -160,6 +197,9 @@
      * @return Snapshot for current thread if there is one.
      */
     private ConcurrentNavigableMap<GridSearchRowPointer, GridH2Row> treeForRead() {
+        if (!snapshotEnabled)
+            return tree;
+
         ConcurrentNavigableMap<GridSearchRowPointer, GridH2Row> res = snapshot.get();
 
         if (res == null)
@@ -199,7 +239,7 @@
 
     /** {@inheritDoc} */
     @Override public long getRowCountApproximation() {
-        return tree.size();
+        return table.getRowCountApproximation();
     }
 
     /** {@inheritDoc} */
@@ -372,7 +412,7 @@
      * Comparable row with bias. Will be used for queries to have correct bounds (in case of multicolumn index
      * and query on few first columns we will multiple equal entries in tree).
      */
-    private class ComparableRow implements GridSearchRowPointer, Comparable<SearchRow> {
+    private final class ComparableRow implements GridSearchRowPointer, Comparable<SearchRow> {
         /** */
         private final SearchRow row;
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
index 7b89824..0c9c8fe 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
@@ -28,6 +28,7 @@
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 import org.apache.ignite.internal.util.typedef.F;
 import org.h2.jdbc.JdbcPreparedStatement;
+import org.h2.util.IntArray;
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.internal.processors.query.h2.sql.GridSqlFunctionType.AVG;
@@ -224,13 +225,23 @@
             rdcQry.distinct(true);
         }
 
-        // Build resulting two step query.
-        GridCacheTwoStepQuery res = new GridCacheTwoStepQuery(spaces, new GridCacheSqlQuery(rdcQry.getSQL(),
-            findParams(rdcQry, params, new ArrayList<>()).toArray()));
+        IntArray paramIdxs = new IntArray(params.length);
 
-        res.addMapQuery(new GridCacheSqlQuery(mapQry.getSQL(),
-            findParams(mapQry, params, new ArrayList<>(params.length)).toArray())
-            .columns(collectColumns(mapExps)));
+        GridCacheSqlQuery rdc = new GridCacheSqlQuery(rdcQry.getSQL(),
+            findParams(rdcQry, params, new ArrayList<>(), paramIdxs).toArray());
+
+        rdc.parameterIndexes(toIntArray(paramIdxs));
+
+        paramIdxs = new IntArray(params.length);
+
+        GridCacheSqlQuery map = new GridCacheSqlQuery(mapQry.getSQL(),
+            findParams(mapQry, params, new ArrayList<>(params.length), paramIdxs).toArray())
+            .columns(collectColumns(mapExps));
+
+        map.parameterIndexes(toIntArray(paramIdxs));
+
+        // Build resulting two step query.
+        GridCacheTwoStepQuery res = new GridCacheTwoStepQuery(spaces, rdc, rdcQry.simpleQuery()).addMapQuery(map);
 
         res.explain(explain);
 
@@ -238,6 +249,16 @@
     }
 
     /**
+     * @param arr Integer array.
+     * @return Primitive int array.
+     */
+    private static int[] toIntArray(IntArray arr) {
+        int[] res = new int[arr.size()];
+        arr.toArray(res);
+        return res;
+    }
+
+    /**
      * @param cols Columns from SELECT clause.
      * @return Map of columns with types.
      */
@@ -341,19 +362,21 @@
      * @param qry Select.
      * @param params Parameters.
      * @param target Extracted parameters.
+     * @param paramIdxs Parameter indexes.
      * @return Extracted parameters list.
      */
-    private static List<Object> findParams(GridSqlQuery qry, Object[] params, ArrayList<Object> target) {
+    private static List<Object> findParams(GridSqlQuery qry, Object[] params, ArrayList<Object> target,
+        IntArray paramIdxs) {
         if (qry instanceof GridSqlSelect)
-            return findParams((GridSqlSelect)qry, params, target);
+            return findParams((GridSqlSelect)qry, params, target, paramIdxs);
 
         GridSqlUnion union = (GridSqlUnion)qry;
 
-        findParams(union.left(), params, target);
-        findParams(union.right(), params, target);
+        findParams(union.left(), params, target, paramIdxs);
+        findParams(union.right(), params, target, paramIdxs);
 
-        findParams(qry.limit(), params, target);
-        findParams(qry.offset(), params, target);
+        findParams(qry.limit(), params, target, paramIdxs);
+        findParams(qry.offset(), params, target, paramIdxs);
 
         return target;
     }
@@ -362,22 +385,24 @@
      * @param qry Select.
      * @param params Parameters.
      * @param target Extracted parameters.
+     * @param paramIdxs Parameter indexes.
      * @return Extracted parameters list.
      */
-    private static List<Object> findParams(GridSqlSelect qry, Object[] params, ArrayList<Object> target) {
+    private static List<Object> findParams(GridSqlSelect qry, Object[] params, ArrayList<Object> target,
+        IntArray paramIdxs) {
         if (params.length == 0)
             return target;
 
         for (GridSqlElement el : qry.columns(false))
-            findParams(el, params, target);
+            findParams(el, params, target, paramIdxs);
 
-        findParams(qry.from(), params, target);
-        findParams(qry.where(), params, target);
+        findParams(qry.from(), params, target, paramIdxs);
+        findParams(qry.where(), params, target, paramIdxs);
 
         // Don't search in GROUP BY and HAVING since they expected to be in select list.
 
-        findParams(qry.limit(), params, target);
-        findParams(qry.offset(), params, target);
+        findParams(qry.limit(), params, target, paramIdxs);
+        findParams(qry.offset(), params, target, paramIdxs);
 
         return target;
     }
@@ -386,15 +411,17 @@
      * @param el Element.
      * @param params Parameters.
      * @param target Extracted parameters.
+     * @param paramIdxs Parameter indexes.
      */
-    private static void findParams(@Nullable GridSqlElement el, Object[] params, ArrayList<Object> target) {
+    private static void findParams(@Nullable GridSqlElement el, Object[] params, ArrayList<Object> target,
+        IntArray paramIdxs) {
         if (el == null)
             return;
 
         if (el instanceof GridSqlParameter) {
             // H2 Supports queries like "select ?5" but first 4 non-existing parameters are need to be set to any value.
             // Here we will set them to NULL.
-            int idx = ((GridSqlParameter)el).index();
+            final int idx = ((GridSqlParameter)el).index();
 
             while (target.size() < idx)
                 target.add(null);
@@ -409,12 +436,14 @@
                 target.add(param);
             else
                 target.set(idx, param);
+
+            paramIdxs.add(idx);
         }
         else if (el instanceof GridSqlSubquery)
-            findParams(((GridSqlSubquery)el).select(), params, target);
+            findParams(((GridSqlSubquery)el).select(), params, target, paramIdxs);
         else
             for (GridSqlElement child : el)
-                findParams(child, params, target);
+                findParams(child, params, target, paramIdxs);
     }
 
     /**
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java
index e537ace..e190c87 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java
@@ -103,6 +103,33 @@
     }
 
     /**
+     * @return {@code True} if this simple SQL query like 'SELECT A, B, C from SOME_TABLE' without any conditions
+     *      and expressions.
+     */
+    public boolean simpleQuery() {
+        boolean simple = !distinct &&
+            from instanceof GridSqlTable &&
+            where == null &&
+            grpCols == null &&
+            havingCol < 0 &&
+            sort.isEmpty() &&
+            limit == null &&
+            offset == null;
+
+        if (simple) {
+            for (GridSqlElement expression : columns(true)) {
+                if (expression instanceof GridSqlAlias)
+                    expression = expression.child();
+
+                if (!(expression instanceof GridSqlColumn))
+                    return false;
+            }
+        }
+
+        return simple;
+    }
+
+    /**
      * @param buff Statement builder.
      * @param expression Alias expression.
      */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
index b4e1932..21541ec 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
@@ -451,8 +451,11 @@
             int i = 0;
 
             for (GridCacheSqlQuery qry : qrys) {
-                ResultSet rs = h2.executeSqlQueryWithTimer(req.space(), h2.connectionForSpace(req.space()), qry.query(),
-                    F.asList(qry.parameters()));
+                ResultSet rs = h2.executeSqlQueryWithTimer(req.space(),
+                    h2.connectionForSpace(req.space()),
+                    qry.query(),
+                    F.asList(qry.parameters()),
+                    true);
 
                 if (ctx.event().isRecordable(EVT_CACHE_QUERY_EXECUTED)) {
                     ctx.event().record(new CacheQueryExecutedEvent<>(
@@ -820,17 +823,7 @@
 
             closed = true;
 
-            Statement stmt;
-
-            try {
-                stmt = rs.getStatement();
-            }
-            catch (SQLException e) {
-                throw new IllegalStateException(e); // Must not happen.
-            }
-
             U.close(rs, log);
-            U.close(stmt, log);
         }
     }
 
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndex.java
index 7f8caed..12c2240 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndex.java
@@ -80,6 +80,13 @@
     }
 
     /**
+     *
+     */
+    protected GridMergeIndex() {
+        // No-op.
+    }
+
+    /**
      * @return Return source nodes for this merge index.
      */
     public Set<UUID> sources() {
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndexUnsorted.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndexUnsorted.java
index 5f5eb25..501480a 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndexUnsorted.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMergeIndexUnsorted.java
@@ -47,6 +47,20 @@
         super(tbl, name, IndexType.createScan(false), IndexColumn.wrap(tbl.getColumns()));
     }
 
+    /**
+     * @return Dummy index instance.
+     */
+    public static GridMergeIndexUnsorted createDummy() {
+        return new GridMergeIndexUnsorted();
+    }
+
+    /**
+     *
+     */
+    private GridMergeIndexUnsorted() {
+        // No-op.
+    }
+
     /** {@inheritDoc} */
     @Override protected void addPage0(GridResultPage page) {
         assert page.rowsInPage() > 0 || page.isLast() || page.isFail();
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
index f515a78..1d4fa30 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
@@ -79,10 +79,12 @@
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.h2.command.ddl.CreateTableData;
 import org.h2.engine.Session;
+import org.h2.index.Cursor;
 import org.h2.jdbc.JdbcConnection;
 import org.h2.jdbc.JdbcResultSet;
 import org.h2.jdbc.JdbcStatement;
 import org.h2.result.ResultInterface;
+import org.h2.result.Row;
 import org.h2.table.Column;
 import org.h2.util.IntArray;
 import org.h2.value.Value;
@@ -184,8 +186,8 @@
                 UUID nodeId = ((DiscoveryEvent)evt).eventNode().id();
 
                 for (QueryRun r : runs.values()) {
-                    for (GridMergeTable tbl : r.tbls) {
-                        if (tbl.getScanIndex(null).hasSource(nodeId)) {
+                    for (GridMergeIndex idx : r.idxs) {
+                        if (idx.hasSource(nodeId)) {
                             handleNodeLeft(r, nodeId);
 
                             break;
@@ -270,7 +272,7 @@
 
         final int pageSize = r.pageSize;
 
-        GridMergeIndex idx = r.tbls.get(msg.query()).getScanIndex(null);
+        GridMergeIndex idx = r.idxs.get(msg.query());
 
         GridResultPage page;
 
@@ -468,7 +470,7 @@
 
             r.pageSize = qry.pageSize() <= 0 ? GridCacheTwoStepQuery.DFLT_PAGE_SIZE : qry.pageSize();
 
-            r.tbls = new ArrayList<>(qry.mapQueries().size());
+            r.idxs = new ArrayList<>(qry.mapQueries().size());
 
             String space = cctx.name();
 
@@ -501,7 +503,7 @@
             assert !nodes.isEmpty();
 
             if (cctx.isReplicated() || qry.explain()) {
-                assert qry.explain() || !nodes.contains(ctx.cluster().get().localNode()) :
+                assert qry.explain() || !nodes.contains(ctx.discovery().localNode()) :
                     "We must be on a client node.";
 
                 // Select random data node to run query on a replicated data or get EXPLAIN PLAN from a single node.
@@ -510,27 +512,35 @@
 
             int tblIdx = 0;
 
+            final boolean skipMergeTbl = !qry.explain() && qry.skipMergeTable();
+
             for (GridCacheSqlQuery mapQry : qry.mapQueries()) {
-                GridMergeTable tbl;
+                GridMergeIndex idx;
 
-                try {
-                    tbl = createMergeTable(r.conn, mapQry, qry.explain());
-                }
-                catch (IgniteCheckedException e) {
-                    throw new IgniteException(e);
-                }
+                if (!skipMergeTbl) {
+                    GridMergeTable tbl;
 
-                GridMergeIndex idx = tbl.getScanIndex(null);
+                    try {
+                        tbl = createMergeTable(r.conn, mapQry, qry.explain());
+                    }
+                    catch (IgniteCheckedException e) {
+                        throw new IgniteException(e);
+                    }
+
+                    idx = tbl.getScanIndex(null);
+
+                    fakeTable(r.conn, tblIdx++).setInnerTable(tbl);
+                }
+                else
+                    idx = GridMergeIndexUnsorted.createDummy();
 
                 for (ClusterNode node : nodes)
                     idx.addSource(node.id());
 
-                r.tbls.add(tbl);
-
-                fakeTable(r.conn, tblIdx++).setInnerTable(tbl);
+                r.idxs.add(idx);
             }
 
-            r.latch = new CountDownLatch(r.tbls.size() * nodes.size());
+            r.latch = new CountDownLatch(r.idxs.size() * nodes.size());
 
             runs.put(qryReqId, r);
 
@@ -586,19 +596,52 @@
                 else // Send failed.
                     retry = true;
 
-                ResultSet res = null;
+                Iterator<List<?>> resIter = null;
 
                 if (!retry) {
                     if (qry.explain())
                         return explainPlan(r.conn, space, qry);
 
-                    GridCacheSqlQuery rdc = qry.reduceQuery();
+                    if (skipMergeTbl) {
+                        List<List<?>> res = new ArrayList<>();
 
-                    res = h2.executeSqlQueryWithTimer(space, r.conn, rdc.query(), F.asList(rdc.parameters()));
+                        assert r.idxs.size() == 1 : r.idxs;
+
+                        GridMergeIndex idx = r.idxs.get(0);
+
+                        Cursor cur = idx.findInStream(null, null);
+
+                        while (cur.next()) {
+                            Row row = cur.get();
+
+                            int cols = row.getColumnCount();
+
+                            List<Object> resRow  = new ArrayList<>(cols);
+
+                            for (int c = 0; c < cols; c++)
+                                resRow.add(row.getValue(c).getObject());
+
+                            res.add(resRow);
+                        }
+
+                        resIter = res.iterator();
+                    }
+                    else {
+                        GridCacheSqlQuery rdc = qry.reduceQuery();
+
+                        // Statement caching is prohibited here because we can't guarantee correct merge index reuse.
+                        ResultSet res = h2.executeSqlQueryWithTimer(space,
+                            r.conn,
+                            rdc.query(),
+                            F.asList(rdc.parameters()),
+                            false);
+
+                        resIter = new Iter(res);
+                    }
                 }
 
-                for (GridMergeTable tbl : r.tbls) {
-                    if (!tbl.getScanIndex(null).fetchedAll()) // We have to explicitly cancel queries on remote nodes.
+                for (GridMergeIndex idx : r.idxs) {
+                    if (!idx.fetchedAll()) // We have to explicitly cancel queries on remote nodes.
                         send(nodes, new GridQueryCancelRequest(qryReqId), null);
                 }
 
@@ -609,7 +652,7 @@
                     continue;
                 }
 
-                return new GridQueryCacheObjectsIterator(new Iter(res), cctx, keepPortable);
+                return new GridQueryCacheObjectsIterator(resIter, cctx, keepPortable);
             }
             catch (IgniteCheckedException | RuntimeException e) {
                 U.closeQuiet(r.conn);
@@ -633,8 +676,10 @@
                 if (!runs.remove(qryReqId, r))
                     U.warn(log, "Query run was already removed: " + qryReqId);
 
-                for (int i = 0, mapQrys = qry.mapQueries().size(); i < mapQrys; i++)
-                    fakeTable(null, i).setInnerTable(null); // Drop all merge tables.
+                if (!skipMergeTbl) {
+                    for (int i = 0, mapQrys = qry.mapQueries().size(); i < mapQrys; i++)
+                        fakeTable(null, i).setInnerTable(null); // Drop all merge tables.
+                }
             }
         }
     }
@@ -941,7 +986,7 @@
         List<List<?>> lists = new ArrayList<>();
 
         for (int i = 0, mapQrys = qry.mapQueries().size(); i < mapQrys; i++) {
-            ResultSet rs = h2.executeSqlQueryWithTimer(space, c, "SELECT PLAN FROM " + table(i), null);
+            ResultSet rs = h2.executeSqlQueryWithTimer(space, c, "SELECT PLAN FROM " + table(i), null, false);
 
             lists.add(F.asList(getPlan(rs)));
         }
@@ -956,7 +1001,11 @@
 
         GridCacheSqlQuery rdc = qry.reduceQuery();
 
-        ResultSet rs = h2.executeSqlQueryWithTimer(space, c, "EXPLAIN " + rdc.query(), F.asList(rdc.parameters()));
+        ResultSet rs = h2.executeSqlQueryWithTimer(space,
+            c,
+            "EXPLAIN " + rdc.query(),
+            F.asList(rdc.parameters()),
+            false);
 
         lists.add(F.asList(getPlan(rs)));
 
@@ -1013,7 +1062,7 @@
         }
 
         if (locNodeFound) // Local node goes the last to allow parallel execution.
-            h2.mapQueryExecutor().onMessage(ctx.localNodeId(), copy(msg, ctx.cluster().get().localNode(), partsMap));
+            h2.mapQueryExecutor().onMessage(ctx.localNodeId(), copy(msg, ctx.discovery().localNode(), partsMap));
 
         return ok;
     }
@@ -1120,7 +1169,7 @@
      */
     private static class QueryRun {
         /** */
-        private List<GridMergeTable> tbls;
+        private List<GridMergeIndex> idxs;
 
         /** */
         private CountDownLatch latch;
@@ -1148,8 +1197,8 @@
             while (latch.getCount() != 0) // We don't need to wait for all nodes to reply.
                 latch.countDown();
 
-            for (GridMergeTable tbl : tbls) // Fail all merge indexes.
-                tbl.getScanIndex(null).fail(nodeId);
+            for (GridMergeIndex idx : idxs) // Fail all merge indexes.
+                idx.fail(nodeId);
         }
 
         /**
@@ -1162,8 +1211,8 @@
             while (latch.getCount() != 0) // We don't need to wait for all nodes to reply.
                 latch.countDown();
 
-            for (GridMergeTable tbl : tbls) // Fail all merge indexes.
-                tbl.getScanIndex(null).fail(e);
+            for (GridMergeIndex idx : idxs) // Fail all merge indexes.
+                idx.fail(e);
         }
     }
 
@@ -1179,7 +1228,7 @@
          * @throws IgniteCheckedException If failed.
          */
         protected Iter(ResultSet data) throws IgniteCheckedException {
-            super(data);
+            super(data, true);
         }
 
         /** {@inheritDoc} */
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
index 9ccb893..07e44da 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
@@ -270,7 +270,7 @@
                     fields = meta.fields("Organization");
 
                     assert fields != null;
-                    assert fields.size() == 4;
+                    assertEquals("Fields: " + fields, 5, fields.size());
                     assert String.class.getName().equals(fields.get("_KEY"));
                     assert Organization.class.getName().equals(fields.get("_VAL"));
                     assert int.class.getName().equals(fields.get("ID"));
@@ -545,7 +545,7 @@
         int cnt = 0;
 
         for (List<?> row : res) {
-            assert row.size() == 9;
+            assertEquals(10, row.size());
 
             if (cnt == 0) {
                 assert new AffinityKey<>("p1", "o1").equals(row.get(0));
@@ -809,6 +809,21 @@
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testMethodAnnotationWithoutGet() throws Exception {
+        QueryCursor<List<?>> qry = grid(0).cache(null)
+            .query(new SqlFieldsQuery("select methodField from Organization where methodField='name-A'")
+            .setPageSize(10));
+
+        List<List<?>> flds = qry.getAll();
+
+        assertEquals(1, flds.size());
+
+        assertEquals("name-A", flds.get(0).get(0));
+    }
+
+    /**
      * @param cacheName Cache name.
      * @throws Exception If failed.
      */
@@ -995,6 +1010,14 @@
             this.name = name;
         }
 
+        /**
+         * @return Generated method value.
+         */
+        @QuerySqlField
+        public String methodField() {
+            return "name-" + name;
+        }
+
         /** {@inheritDoc} */
         @Override public boolean equals(Object o) {
             if (this == o)
@@ -1018,4 +1041,4 @@
             return res;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
index f3fbf15..79c41f8 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
@@ -156,36 +156,38 @@
                 if (i > 0)
                     cc.setName("c" + i);
 
-            cc.setCacheMode(cacheMode());
-            cc.setAtomicityMode(atomicityMode());
-            cc.setNearConfiguration(nearCacheConfiguration());
-            cc.setWriteSynchronizationMode(FULL_SYNC);
-            cc.setCacheStoreFactory(new StoreFactory());
-            cc.setReadThrough(true);
-            cc.setWriteThrough(true);
-            cc.setLoadPreviousValue(true);
-            cc.setRebalanceMode(SYNC);
-            cc.setSwapEnabled(true);
-            cc.setSqlFunctionClasses(SqlFunctions.class);
-            cc.setIndexedTypes(
-                BadHashKeyObject.class, Byte.class,
-                ObjectValue.class, Long.class,
-                Integer.class, Integer.class,
-                Integer.class, String.class,
-                Integer.class, ObjectValue.class,
-                String.class, ObjectValueOther.class,
-                Integer.class, ArrayObject.class,
-                Key.class, GridCacheQueryTestValue.class,
-                UUID.class, Person.class,
-                IgniteCacheReplicatedQuerySelfTest.CacheKey.class, IgniteCacheReplicatedQuerySelfTest.CacheValue.class
-            );
+                cc.setCacheMode(cacheMode());
+                cc.setAtomicityMode(atomicityMode());
+                cc.setNearConfiguration(nearCacheConfiguration());
+                cc.setWriteSynchronizationMode(FULL_SYNC);
+                cc.setCacheStoreFactory(new StoreFactory());
+                cc.setReadThrough(true);
+                cc.setWriteThrough(true);
+                cc.setLoadPreviousValue(true);
+                cc.setRebalanceMode(SYNC);
+                cc.setSwapEnabled(true);
+                cc.setSqlFunctionClasses(SqlFunctions.class);
+                cc.setIndexedTypes(
+                    BadHashKeyObject.class, Byte.class,
+                    ObjectValue.class, Long.class,
+                    Integer.class, Integer.class,
+                    Integer.class, String.class,
+                    Integer.class, ObjectValue.class,
+                    String.class, ObjectValueOther.class,
+                    Integer.class, ArrayObject.class,
+                    Key.class, GridCacheQueryTestValue.class,
+                    UUID.class, Person.class,
+                    IgniteCacheReplicatedQuerySelfTest.CacheKey.class, IgniteCacheReplicatedQuerySelfTest.CacheValue.class
+                );
 
-            if (cacheMode() != CacheMode.LOCAL)
-                cc.setAffinity(new RendezvousAffinityFunction());
+                if (cacheMode() != CacheMode.LOCAL)
+                    cc.setAffinity(new RendezvousAffinityFunction());
 
-            // Explicitly set number of backups equal to number of grids.
-            if (cacheMode() == CacheMode.PARTITIONED)
-                cc.setBackups(gridCount());
+                // Explicitly set number of backups equal to number of grids.
+                if (cacheMode() == CacheMode.PARTITIONED)
+                    cc.setBackups(gridCount());
+
+                cc.setSnapshotableIndex(snapshotableIndex());
 
                 ccs[i] = cc;
             }
@@ -198,6 +200,13 @@
         return c;
     }
 
+    /**
+     * @return {@code True} if index snapshot is enabled.
+     */
+    protected boolean snapshotableIndex() {
+        return false;
+    }
+
     /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         ignite = startGridsMultiThreaded(gridCount());
@@ -1372,7 +1381,7 @@
         /**
          * @return Salary.
          */
-        public double salary() {
+        public int salary() {
             return salary;
         }
 
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheNoClassQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheNoClassQuerySelfTest.java
new file mode 100644
index 0000000..9429226
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheNoClassQuerySelfTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ *
+ */
+public class IgniteCacheNoClassQuerySelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    protected Ignite ignite;
+
+    /**
+     * @return Atomicity mode.
+     */
+    protected CacheAtomicityMode atomicityMode() {
+        return TRANSACTIONAL;
+    }
+
+    /**
+     * @return Distribution.
+     */
+    protected NearCacheConfiguration nearCacheConfiguration() {
+        return new NearCacheConfiguration();
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration c = super.getConfiguration(gridName);
+
+        c.setDiscoverySpi(new TcpDiscoverySpi().setForceServerMode(true).setIpFinder(ipFinder));
+
+        CacheConfiguration cc = defaultCacheConfiguration();
+
+        c.setMarshaller(new OptimizedMarshaller());
+
+        cc.setName("cache");
+
+        cc.setAtomicityMode(TRANSACTIONAL);
+        cc.setWriteSynchronizationMode(FULL_SYNC);
+        cc.setRebalanceMode(SYNC);
+
+        QueryEntity qryEntity = new QueryEntity();
+
+        qryEntity.setKeyType(Integer.class.getName());
+        qryEntity.setValueType("MyClass");
+
+        LinkedHashMap<String, String> fields = new LinkedHashMap<>();
+
+        fields.put("strField", String.class.getName());
+        fields.put("intField", Integer.class.getName());
+        fields.put("doubleField", Double.class.getName());
+
+        qryEntity.setFields(fields);
+
+        qryEntity.setFields(fields);
+
+        qryEntity.setIndexes(Arrays.asList(
+            new QueryIndex("strField"),
+            new QueryIndex("intField"),
+            new QueryIndex("doubleField")
+        ));
+
+        cc.setQueryEntities(Collections.singletonList(
+            qryEntity
+        ));
+
+        c.setCacheConfiguration(cc);
+
+        return c;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testNoClass() throws Exception {
+        try {
+            startGrid();
+        }
+        catch (Exception e) {
+            assertTrue(e.getMessage().contains("default marshaller"));
+        }
+    }
+}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
index 4d9456a..6f8ca2d 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
@@ -19,15 +19,14 @@
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import javax.cache.CacheException;
 import org.apache.ignite.cache.query.ScanQuery;
 import org.apache.ignite.cache.query.SqlQuery;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
 
 /**
  * Checks behavior on exception while unmarshalling key.
@@ -68,8 +67,6 @@
     public void testResponseMessageOnRequestUnmarshallingFailed() throws Exception {
         readCnt.set(Integer.MAX_VALUE);
 
-        jcache(0).put(new TestKey(String.valueOf(++key)), "");
-
         try {
             jcache().query(new ScanQuery<>(new IgniteBiPredicate<TestKey, String>() {
                 @Override public boolean apply(TestKey key, String val) {
@@ -79,6 +76,10 @@
                 private void readObject(ObjectInputStream is) throws IOException {
                     throw new IOException();
                 }
+
+                private void writeObject(ObjectOutputStream os) throws IOException {
+                    throw new IOException();
+                }
             })).getAll();
 
             assertTrue("Request unmarshalling failed, but error response was not sent.", portableMarshaller());
diff --git a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCachePartitionedSnapshotEnabledQuerySelfTest.java
similarity index 73%
copy from examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
copy to modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCachePartitionedSnapshotEnabledQuerySelfTest.java
index 6548210..9a68b16 100644
--- a/examples/src/main/java/org/apache/ignite/examples/binary/OrganizationType.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/IgniteCachePartitionedSnapshotEnabledQuerySelfTest.java
@@ -15,18 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.examples.binary;
+package org.apache.ignite.internal.processors.cache.distributed.near;
 
 /**
- * Organization type enum.
+ *
  */
-public enum OrganizationType {
-    /** Non-profit organization. */
-    NON_PROFIT,
-
-    /** Private organization. */
-    PRIVATE,
-
-    /** Government organization. */
-    GOVERNMENT
+public class IgniteCachePartitionedSnapshotEnabledQuerySelfTest extends IgniteCachePartitionedQuerySelfTest {
+    /** {@inheritDoc} */
+    @Override protected boolean snapshotableIndex() {
+        return true;
+    }
 }
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java
index 194fb82..c027b26 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/GridIndexingSpiAbstractSelfTest.java
@@ -34,6 +34,7 @@
 import org.apache.ignite.internal.processors.query.GridQueryFieldsResult;
 import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
 import org.apache.ignite.internal.processors.query.GridQueryIndexType;
+import org.apache.ignite.internal.processors.query.GridQueryProperty;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -505,6 +506,24 @@
         }
 
         /** {@inheritDoc} */
+        @Override public GridQueryProperty property(final String name) {
+            return new GridQueryProperty() {
+                @Override public Object value(Object key, Object val) throws IgniteCheckedException {
+                    return TypeDesc.this.value(name, key, val);
+                }
+
+                @Override public String name() {
+                    return name;
+                }
+
+                @Override
+                public Class<?> type() {
+                    return Object.class;
+                }
+            };
+        }
+
+        /** {@inheritDoc} */
         @SuppressWarnings("unchecked")
         @Override public <T> T value(String field, Object key, Object val) throws IgniteSpiException {
             assert !F.isEmpty(field);
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
index 6cc2599..8311414 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
@@ -33,6 +33,7 @@
 import org.apache.ignite.internal.processors.cache.IgniteCacheCollocatedQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheFieldsQueryNoDataSelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheLargeResultSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheNoClassQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapEvictQueryTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapTieredMultithreadedSelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheP2pUnmarshallingQueryErrorTest;
@@ -55,6 +56,7 @@
 import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCachePartitionedFieldsQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCachePartitionedQueryP2PDisabledSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCachePartitionedQuerySelfTest;
+import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCachePartitionedSnapshotEnabledQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCacheQueryNodeRestartSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCacheQueryNodeRestartSelfTest2;
 import org.apache.ignite.internal.processors.cache.distributed.replicated.IgniteCacheReplicatedFieldsQueryP2PEnabledSelfTest;
@@ -118,6 +120,7 @@
         suite.addTestSuite(IgniteCacheReplicatedQuerySelfTest.class);
         suite.addTestSuite(IgniteCacheReplicatedQueryP2PDisabledSelfTest.class);
         suite.addTestSuite(IgniteCachePartitionedQuerySelfTest.class);
+        suite.addTestSuite(IgniteCachePartitionedSnapshotEnabledQuerySelfTest.class);
         suite.addTestSuite(IgniteCacheAtomicQuerySelfTest.class);
         suite.addTestSuite(IgniteCacheAtomicNearEnabledQuerySelfTest.class);
         suite.addTestSuite(IgniteCachePartitionedQueryP2PDisabledSelfTest.class);
@@ -202,6 +205,7 @@
 
         //Unmarshallig query test.
         suite.addTestSuite(IgniteCacheP2pUnmarshallingQueryErrorTest.class);
+        suite.addTestSuite(IgniteCacheNoClassQuerySelfTest.class);
 
         return suite;
     }
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheQueryTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheQueryTestSuite.java
index b241b86..4e9be93 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheQueryTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgnitePortableCacheQueryTestSuite.java
@@ -45,7 +45,7 @@
 import org.apache.ignite.internal.processors.query.h2.sql.BaseH2CompareQueryTest;
 import org.apache.ignite.internal.processors.query.h2.sql.GridQueryParsingTest;
 import org.apache.ignite.internal.processors.query.h2.sql.H2CompareBigQueryTest;
-import org.apache.ignite.marshaller.portable.BinaryMarshaller;
+import org.apache.ignite.internal.portable.BinaryMarshaller;
 import org.apache.ignite.spi.communication.tcp.GridOrderedMessageCancelSelfTest;
 import org.apache.ignite.testframework.config.GridTestProperties;
 
diff --git a/modules/jms11/README.txt b/modules/jms11/README.txt
new file mode 100644
index 0000000..3f0d213
--- /dev/null
+++ b/modules/jms11/README.txt
@@ -0,0 +1,29 @@
+Apache Ignite JMS 1.1 Module
+----------------------------
+
+Apache Ignite JMS 1.1 module provides a streamer to consume JMS queue and topic messages into
+Apache Ignite caches.
+
+Importing Apache Ignite JMS 1.1 Module In Maven Project
+--------------------------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add the JMS 1.1 module
+dependency like this (replace '${ignite.version}' with actual Ignite version you are
+interested in):
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    ...
+    <dependencies>
+        ...
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-jms11</artifactId>
+            <version>${ignite.version}</version>
+        </dependency>
+        ...
+    </dependencies>
+    ...
+</project>
diff --git a/modules/jms11/licenses/apache-2.0.txt b/modules/jms11/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/jms11/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/modules/jms11/src/main/java/org/apache/ignite/stream/jms11/package-info.java b/modules/jms11/src/main/java/org/apache/ignite/stream/jms11/package-info.java
new file mode 100644
index 0000000..b3393ee
--- /dev/null
+++ b/modules/jms11/src/main/java/org/apache/ignite/stream/jms11/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of JMS queue and topic messages consumer.
+ */
+package org.apache.ignite.stream.jms11;
\ No newline at end of file
diff --git a/modules/jms11/src/test/java/org/apache/ignite/stream/jms11/package-info.java b/modules/jms11/src/test/java/org/apache/ignite/stream/jms11/package-info.java
new file mode 100644
index 0000000..b3393ee
--- /dev/null
+++ b/modules/jms11/src/test/java/org/apache/ignite/stream/jms11/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of JMS queue and topic messages consumer.
+ */
+package org.apache.ignite.stream.jms11;
\ No newline at end of file
diff --git a/modules/kafka/README.txt b/modules/kafka/README.txt
new file mode 100644
index 0000000..1eaf861
--- /dev/null
+++ b/modules/kafka/README.txt
@@ -0,0 +1,32 @@
+Apache Ignite Kafka Streamer Module
+------------------------
+
+Apache Ignite Kafka Streamer module provides streaming from Kafka to Ignite cache.
+
+To enable Kafka Streamer module when starting a standalone node, move 'optional/ignite-Kafka' folder to
+'libs' folder before running 'ignite.{sh|bat}' script. The content of the module folder will
+be added to classpath in this case.
+
+Importing Ignite Kafka Streamer Module In Maven Project
+-------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add JCL module
+dependency like this (replace '${ignite.version}' with actual Ignite version you are
+interested in):
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    ...
+    <dependencies>
+        ...
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-kafka</artifactId>
+            <version>${ignite.version}</version>
+        </dependency>
+        ...
+    </dependencies>
+    ...
+</project>
diff --git a/modules/kafka/src/main/java/org/apache/ignite/stream/kafka/package-info.java b/modules/kafka/src/main/java/org/apache/ignite/stream/kafka/package-info.java
new file mode 100644
index 0000000..3b76237
--- /dev/null
+++ b/modules/kafka/src/main/java/org/apache/ignite/stream/kafka/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Kafka Streamer.
+ */
+package org.apache.ignite.stream.kafka;
\ No newline at end of file
diff --git a/modules/kafka/src/test/java/org/apache/ignite/stream/kafka/package-info.java b/modules/kafka/src/test/java/org/apache/ignite/stream/kafka/package-info.java
new file mode 100644
index 0000000..3b76237
--- /dev/null
+++ b/modules/kafka/src/test/java/org/apache/ignite/stream/kafka/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Kafka Streamer.
+ */
+package org.apache.ignite.stream.kafka;
\ No newline at end of file
diff --git a/modules/mqtt/README.txt b/modules/mqtt/README.txt
new file mode 100644
index 0000000..62a1589
--- /dev/null
+++ b/modules/mqtt/README.txt
@@ -0,0 +1,29 @@
+Apache Ignite MQTT Module
+-------------------------
+
+Apache Ignite MQTT module provides a streamer to consume MQTT topic messages into
+Apache Ignite caches.
+
+Importing Apache Ignite MQTT Module In Maven Project
+----------------------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add the MQTT module
+dependency like this (replace '${ignite.version}' with actual Ignite version you are
+interested in):
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    ...
+    <dependencies>
+        ...
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-mqtt</artifactId>
+            <version>${ignite.version}</version>
+        </dependency>
+        ...
+    </dependencies>
+    ...
+</project>
diff --git a/modules/mqtt/licenses/apache-2.0.txt b/modules/mqtt/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/mqtt/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/modules/mqtt/src/main/java/org/apache/ignite/stream/mqtt/package-info.java b/modules/mqtt/src/main/java/org/apache/ignite/stream/mqtt/package-info.java
new file mode 100644
index 0000000..67b949a
--- /dev/null
+++ b/modules/mqtt/src/main/java/org/apache/ignite/stream/mqtt/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of MQTT topic messages consumer.
+ */
+package org.apache.ignite.stream.mqtt;
\ No newline at end of file
diff --git a/modules/mqtt/src/test/java/org/apache/ignite/stream/mqtt/package-info.java b/modules/mqtt/src/test/java/org/apache/ignite/stream/mqtt/package-info.java
new file mode 100644
index 0000000..67b949a
--- /dev/null
+++ b/modules/mqtt/src/test/java/org/apache/ignite/stream/mqtt/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of MQTT topic messages consumer.
+ */
+package org.apache.ignite.stream.mqtt;
\ No newline at end of file
diff --git a/modules/platforms/README.txt b/modules/platforms/README.txt
new file mode 100644
index 0000000..6268a88
--- /dev/null
+++ b/modules/platforms/README.txt
@@ -0,0 +1,6 @@
+Apache Ignite Platforms
+==================================
+
+Contains integrations with other platforms, most notably:
+ * Apache Ignite.NET
+ * Apache Ignite C++
\ No newline at end of file
diff --git a/modules/platforms/cpp/core/src/impl/binary/binary_type_updater_impl.cpp b/modules/platforms/cpp/core/src/impl/binary/binary_type_updater_impl.cpp
index 2e86ccd..6c3bf7f 100644
--- a/modules/platforms/cpp/core/src/impl/binary/binary_type_updater_impl.cpp
+++ b/modules/platforms/cpp/core/src/impl/binary/binary_type_updater_impl.cpp
@@ -32,7 +32,7 @@
     {
         namespace binary
         {
-            /** Operation: Clear. */
+            /** Operation: metadata update. */
             const int32_t OP_METADATA = -1;
 
             BinaryTypeUpdaterImpl::BinaryTypeUpdaterImpl(SharedPointer<IgniteEnvironment> env,
@@ -78,6 +78,8 @@
                 else
                     rawWriter.WriteInt32(0);
 
+                rawWriter.WriteBool(false); // Enums are not supported for now.
+
                 out.Synchronize();
 
                 long long res = env.Get()->Context()->TargetInStreamOutLong(javaRef, OP_METADATA, mem.Get()->PointerLong(), &jniErr);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
index ea472eb..373e173 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryBuilderSelfTest.cs
@@ -80,24 +80,13 @@
                         new BinaryTypeConfiguration(typeof (BuilderCollection)),
                         new BinaryTypeConfiguration(typeof (BuilderCollectionItem)),
                         new BinaryTypeConfiguration(typeof (DecimalHolder)),
-                        new BinaryTypeConfiguration(TypeEmpty)
+                        new BinaryTypeConfiguration(TypeEmpty),
+                        new BinaryTypeConfiguration(typeof(TestEnumRegistered))
                     },
                     DefaultIdMapper = new IdMapper()
                 },
                 JvmClasspath = TestUtils.CreateTestClasspath(),
-                JvmOptions = new List<string>
-                {
-                    "-ea",
-                    "-Xcheck:jni",
-                    "-Xms4g",
-                    "-Xmx4g",
-                    "-DIGNITE_QUIET=false",
-                    "-Xnoagent",
-                    "-Djava.compiler=NONE",
-                    "-Xdebug",
-                    "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005",
-                    "-XX:+HeapDumpOnOutOfMemoryError"
-                },
+                JvmOptions = TestUtils.TestJavaOptions(),
                 SpringConfigUrl = "config\\binary.xml"
             };
 
@@ -198,7 +187,7 @@
             DateTime date = DateTime.Now.ToUniversalTime();
             Guid guid = Guid.NewGuid();
 
-            IIgniteBinary api = _grid.GetBinary();
+            IBinary api = _grid.GetBinary();
 
             // 1. Primitives.
             Assert.AreEqual(1, api.ToBinary<byte>((byte)1));
@@ -216,7 +205,8 @@
             Assert.AreEqual("a", api.ToBinary<string>("a"));
             Assert.AreEqual(date, api.ToBinary<DateTime>(date));
             Assert.AreEqual(guid, api.ToBinary<Guid>(guid));
-            Assert.AreEqual(TestEnum.One, api.ToBinary<TestEnum>(TestEnum.One));
+            Assert.AreEqual(TestEnumRegistered.One, api.ToBinary<IBinaryObject>(TestEnumRegistered.One)
+                .Deserialize<TestEnumRegistered>());
 
             // 3. Arrays.
             Assert.AreEqual(new byte[] { 1 }, api.ToBinary<byte[]>(new byte[] { 1 }));
@@ -233,7 +223,9 @@
             Assert.AreEqual(new[] { "a" }, api.ToBinary<string[]>(new[] { "a" }));
             Assert.AreEqual(new[] { date }, api.ToBinary<DateTime[]>(new[] { date }));
             Assert.AreEqual(new[] { guid }, api.ToBinary<Guid[]>(new[] { guid }));
-            Assert.AreEqual(new[] { TestEnum.One }, api.ToBinary<TestEnum[]>(new[] { TestEnum.One }));
+            Assert.AreEqual(new[] { TestEnumRegistered.One},
+                api.ToBinary<IBinaryObject[]>(new[] { TestEnumRegistered.One})
+                .Select(x => x.Deserialize<TestEnumRegistered>()).ToArray());
 
             // 4. Objects.
             IBinaryObject binObj = api.ToBinary<IBinaryObject>(new ToBinary(1));
@@ -816,7 +808,7 @@
             Assert.AreEqual(new[] { "str" }, binObj.GetField<string[]>("fStrArr"));
             Assert.AreEqual(new[] { nDate }, binObj.GetField<DateTime?[]>("fDateArr"));
             Assert.AreEqual(new[] { nGuid }, binObj.GetField<Guid?[]>("fGuidArr"));
-            Assert.AreEqual(new[] { TestEnum.One }, binObj.GetField<TestEnum[]>("fEnumArr"));
+            Assert.AreEqual(new[] {TestEnum.One}, binObj.GetField<TestEnum[]>("fEnumArr"));
 
             StringDateGuidEnum obj = binObj.Deserialize<StringDateGuidEnum>();
 
@@ -839,7 +831,7 @@
             Assert.AreEqual(new[] { "str" }, builder.GetField<string[]>("fStrArr"));
             Assert.AreEqual(new[] { nDate }, builder.GetField<DateTime?[]>("fDateArr"));
             Assert.AreEqual(new[] { nGuid }, builder.GetField<Guid?[]>("fGuidArr"));
-            Assert.AreEqual(new[] { TestEnum.One }, builder.GetField<TestEnum[]>("fEnumArr"));
+            Assert.AreEqual(new[] {TestEnum.One}, builder.GetField<TestEnum[]>("fEnumArr"));
 
             // Check reassemble.
             binObj = builder.Build();
@@ -851,7 +843,7 @@
             Assert.AreEqual(new[] { "str" }, binObj.GetField<string[]>("fStrArr"));
             Assert.AreEqual(new[] { nDate }, binObj.GetField<DateTime?[]>("fDateArr"));
             Assert.AreEqual(new[] { nGuid }, binObj.GetField<Guid?[]>("fGuidArr"));
-            Assert.AreEqual(new[] { TestEnum.One }, binObj.GetField<TestEnum[]>("fEnumArr"));
+            Assert.AreEqual(new[] {TestEnum.One}, binObj.GetField<TestEnum[]>("fEnumArr"));
 
             obj = binObj.Deserialize<StringDateGuidEnum>();
 
@@ -889,7 +881,7 @@
             Assert.AreEqual(new[] { "str2" }, binObj.GetField<string[]>("fStrArr"));
             Assert.AreEqual(new[] { nDate }, binObj.GetField<DateTime?[]>("fDateArr"));
             Assert.AreEqual(new[] { nGuid }, binObj.GetField<Guid?[]>("fGuidArr"));
-            Assert.AreEqual(new[] { TestEnum.Two }, binObj.GetField<TestEnum[]>("fEnumArr"));
+            Assert.AreEqual(new[] {TestEnum.Two}, binObj.GetField<TestEnum[]>("fEnumArr"));
 
             obj = binObj.Deserialize<StringDateGuidEnum>();
 
@@ -903,6 +895,24 @@
             Assert.AreEqual(new[] { TestEnum.Two }, obj.FEnumArr);
         }
 
+        [Test]
+        public void TestEnumMeta()
+        {
+            var bin = _grid.GetBinary();
+
+            // Put to cache to populate metas
+            var binEnum = bin.ToBinary<IBinaryObject>(TestEnumRegistered.One);
+
+            Assert.AreEqual(_marsh.GetDescriptor(typeof (TestEnumRegistered)).TypeId, binEnum.GetBinaryType().TypeId);
+            Assert.AreEqual(0, binEnum.EnumValue);
+
+            var meta = binEnum.GetBinaryType();
+
+            Assert.IsTrue(meta.IsEnum);
+            Assert.AreEqual(typeof (TestEnumRegistered).Name, meta.TypeName);
+            Assert.AreEqual(0, meta.Fields.Count);
+        }
+
         /// <summary>
         /// Test arrays.
         /// </summary>
@@ -923,7 +933,7 @@
 
             Assert.AreEqual(100, binObj.GetHashCode());
 
-            var binInArr = binObj.GetField<object[]>("inArr").Cast<IBinaryObject>().ToArray();
+            var binInArr = binObj.GetField<IBinaryObject[]>("inArr").ToArray();
 
             Assert.AreEqual(1, binInArr.Length);
             Assert.AreEqual(1, binInArr[0].GetField<int>("val"));
@@ -936,11 +946,11 @@
 
             // 2. Test addition to array.
             binObj = _grid.GetBinary().GetBuilder(binObj).SetHashCode(200)
-                .SetField("inArr", new object[] { binInArr[0], null }).Build();
+                .SetField("inArr", new[] { binInArr[0], null }).Build();
 
             Assert.AreEqual(200, binObj.GetHashCode());
 
-            binInArr = binObj.GetField<object[]>("inArr").Cast<IBinaryObject>().ToArray();
+            binInArr = binObj.GetField<IBinaryObject[]>("inArr").ToArray();
 
             Assert.AreEqual(2, binInArr.Length);
             Assert.AreEqual(1, binInArr[0].GetField<int>("val"));
@@ -960,7 +970,7 @@
 
             Assert.AreEqual(300, binObj.GetHashCode());
 
-            binInArr = binObj.GetField<object[]>("inArr").Cast<IBinaryObject>().ToArray();
+            binInArr = binObj.GetField<IBinaryObject[]>("inArr").ToArray();
 
             Assert.AreEqual(2, binInArr.Length);
             Assert.AreEqual(1, binInArr[0].GetField<int>("val"));
@@ -983,7 +993,7 @@
 
             Assert.AreEqual(100, binObj.GetHashCode());
 
-            binInArr = binObj.GetField<object[]>("inArr").Cast<IBinaryObject>().ToArray();
+            binInArr = binObj.GetField<IBinaryObject[]>("inArr").ToArray();
 
             Assert.AreEqual(2, binInArr.Length);
             Assert.AreEqual(1, binInArr[0].GetField<int>("val"));
@@ -1003,7 +1013,7 @@
 
             Assert.AreEqual(200, binObj.GetHashCode());
 
-            binInArr = binObj.GetField<object[]>("inArr").Cast<IBinaryObject>().ToArray();
+            binInArr = binObj.GetField<IBinaryObject[]>("inArr").ToArray();
 
             Assert.AreEqual(2, binInArr.Length);
             Assert.AreEqual(2, binInArr[0].GetField<int>("val"));
@@ -1031,7 +1041,7 @@
 
             Assert.AreEqual(100, binObj.GetHashCode());
 
-            var binOutArr = binObj.GetField<object[]>("outArr").Cast<IBinaryObject>().ToArray();
+            var binOutArr = binObj.GetField<IBinaryObject[]>("outArr").ToArray();
 
             Assert.AreEqual(2, binOutArr.Length);
             Assert.AreEqual(1, binOutArr[0].GetField<IBinaryObject>("inner").GetField<int>("val"));
@@ -1052,7 +1062,7 @@
 
             Assert.AreEqual(200, binObj.GetHashCode());
 
-            binInArr = binObj.GetField<object[]>("outArr").Cast<IBinaryObject>().ToArray();
+            binInArr = binObj.GetField<IBinaryObject[]>("outArr").ToArray();
 
             Assert.AreEqual(2, binInArr.Length);
             Assert.AreEqual(2, binOutArr[0].GetField<IBinaryObject>("inner").GetField<int>("val"));
@@ -1387,6 +1397,27 @@
 
             Assert.AreEqual(new[] {"val", "valArr"}, decimalMeta.Fields);
         }
+
+        [Test]
+        public void TestBuildEnum()
+        {
+            var binary = _grid.GetBinary();
+
+            int val = (int) TestEnumRegistered.Two;
+
+            var binEnums = new[]
+            {
+                binary.BuildEnum(typeof (TestEnumRegistered), val),
+                binary.BuildEnum(typeof (TestEnumRegistered).Name, val)
+            };
+
+            foreach (var binEnum in binEnums)
+            {
+                Assert.IsTrue(binEnum.GetBinaryType().IsEnum);
+                Assert.AreEqual(val, binEnum.EnumValue);
+                Assert.AreEqual((TestEnumRegistered)val, binEnum.Deserialize<TestEnumRegistered>());
+            }
+        }
     }
 
     /// <summary>
@@ -1452,6 +1483,14 @@
     }
 
     /// <summary>
+    /// Registered enumeration.
+    /// </summary>
+    public enum TestEnumRegistered
+    {
+        One, Two
+    }
+
+    /// <summary>
     /// binary with raw data.
     /// </summary>
     public class WithRaw : IBinarizable
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
index f7455be..88328ec 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs
@@ -25,6 +25,7 @@
     using System;
     using System.Collections;
     using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
     using System.Linq;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Common;
@@ -479,11 +480,18 @@
         * <summary>Check write of enum.</summary>
         */
         [Test]
+        [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull")]
         public void TestWriteEnum()
         {
             TestEnum val = TestEnum.Val1;
 
             Assert.AreEqual(_marsh.Unmarshal<TestEnum>(_marsh.Marshal(val)), val);
+
+            TestEnum? val2 = TestEnum.Val1;
+            Assert.AreEqual(_marsh.Unmarshal<TestEnum?>(_marsh.Marshal(val2)), val2);
+
+            val2 = null;
+            Assert.AreEqual(_marsh.Unmarshal<TestEnum?>(_marsh.Marshal(val2)), val2);
         }
 
         /// <summary>
@@ -500,7 +508,13 @@
 
             TestEnum val = TestEnum.Val1;
 
-            Assert.AreEqual(marsh.Unmarshal<TestEnum>(marsh.Marshal(val)), val);
+            var data = marsh.Marshal(val);
+
+            Assert.AreEqual(marsh.Unmarshal<TestEnum>(data), val);
+
+            var binEnum = marsh.Unmarshal<IBinaryObject>(data, true);
+
+            Assert.AreEqual(val, (TestEnum) binEnum.EnumValue);
         }
 
         /**
@@ -668,8 +682,13 @@
 
             IBinaryObject portNewObj = marsh.Unmarshal<IBinaryObject>(data, BinaryMode.ForceBinary);
 
+            Assert.IsTrue(portNewObj.HasField("field1"));
+            Assert.IsTrue(portNewObj.HasField("field2"));
+            Assert.IsFalse(portNewObj.HasField("field3"));
+
             Assert.AreEqual(obj.Field1, portNewObj.GetField<int>("field1"));
             Assert.AreEqual(obj.Field2, portNewObj.GetField<int>("Field2"));
+            Assert.AreEqual(0, portNewObj.GetField<int>("field3"));
         }
 
         /**
@@ -881,8 +900,11 @@
             Marshaller marsh =
                 new Marshaller(new BinaryConfiguration
                 {
-                    TypeConfigurations =
-                        new List<BinaryTypeConfiguration> {new BinaryTypeConfiguration(typeof (EnumType))}
+                    TypeConfigurations = new[]
+                    {
+                        new BinaryTypeConfiguration(typeof (EnumType)),
+                        new BinaryTypeConfiguration(typeof (TestEnum))
+                    }
                 });
 
             EnumType obj = new EnumType
@@ -897,6 +919,19 @@
 
             Assert.AreEqual(obj.GetHashCode(), portObj.GetHashCode());
 
+            // Test enum field in binary form
+            var binEnum = portObj.GetField<IBinaryObject>("PEnum");
+            Assert.AreEqual(obj.PEnum.GetHashCode(), binEnum.GetHashCode());
+            Assert.AreEqual((int) obj.PEnum, binEnum.EnumValue);
+            Assert.AreEqual(obj.PEnum, binEnum.Deserialize<TestEnum>());
+            Assert.AreEqual(obj.PEnum, binEnum.Deserialize<object>());
+            Assert.AreEqual(typeof(TestEnum), binEnum.Deserialize<object>().GetType());
+            Assert.AreEqual(null, binEnum.GetField<object>("someField"));
+            Assert.IsFalse(binEnum.HasField("anyField"));
+
+            var binEnumArr = portObj.GetField<IBinaryObject[]>("PEnumArray");
+            Assert.IsTrue(binEnumArr.Select(x => x.Deserialize<TestEnum>()).SequenceEqual(obj.PEnumArray));
+
             EnumType newObj = portObj.Deserialize<EnumType>();
 
             Assert.AreEqual(obj.PEnum, newObj.PEnum);
@@ -1094,7 +1129,7 @@
             inner.RawOuter = outer;
 
             var bytes = asbinary
-                ? marsh.Marshal(new IgniteBinary(marsh).ToBinary<IBinaryObject>(outer))
+                ? marsh.Marshal(new Binary(marsh).ToBinary<IBinaryObject>(outer))
                 : marsh.Marshal(outer);
 
             IBinaryObject outerObj;
@@ -2057,6 +2092,11 @@
             Val1, Val2, Val3 = 10
         }
 
+        public enum TestEnum2
+        {
+            Val1, Val2, Val3 = 10
+        }
+
         public class DecimalReflective
         {
             /** */
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
index 64124d7..ce15739 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs
@@ -347,17 +347,16 @@
             for (int i = 0; i < GridCount(); i++)
             {
                 var cache = Cache(i);
+                var entries = cache.Select(pair => pair.ToString() + GetKeyAffinity(cache, pair.Key)).ToArray();
 
-                if (!cache.IsEmpty())
-                {
-                    var entries = Enumerable.Range(0, 2000)
-                        .Select(x => new KeyValuePair<int, int>(x, cache.LocalPeek(x)))
-                        .Where(x => x.Value != 0)
-                        .Select(pair => pair.ToString() + GetKeyAffinity(cache, pair.Key))
-                        .Aggregate((acc, val) => string.Format("{0}, {1}", acc, val));
+                if (entries.Any())
+                    Assert.Fail("Cache '{0}' is not empty in grid [{1}]: ({2})", CacheName(), i,
+                        entries.Aggregate((acc, val) => string.Format("{0}, {1}", acc, val)));
 
-                    Assert.Fail("Cache '{0}' is not empty in grid [{1}]: ({2})", CacheName(), i, entries);
-                }
+                var size = cache.GetSize();
+                Assert.AreEqual(0, size,
+                    "Cache enumerator returned no entries, but cache '{0}' size is {1} in grid [{2}]",
+                    CacheName(), size, i);
             }
 
             Console.WriteLine("Test finished: " + TestContext.CurrentContext.Test.Name);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
index 1e999e3..87b7f9d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
@@ -899,6 +899,12 @@
 
             var res = _grid1.GetCompute().ExecuteJavaTask<PlatformComputeEnum>(EchoTask, EchoTypeEnumField);
 
+            var enumMeta = _grid1.GetBinary().GetBinaryType(typeof (PlatformComputeEnum));
+
+            Assert.IsTrue(enumMeta.IsEnum);
+            Assert.AreEqual(enumMeta.TypeName, typeof(PlatformComputeEnum).Name);
+            Assert.AreEqual(0, enumMeta.Fields.Count);
+
             Assert.AreEqual(enumVal, res);
         }
 
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Compute/compute-grid1.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Compute/compute-grid1.xml
index 79909c3..3061773 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Compute/compute-grid1.xml
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Compute/compute-grid1.xml
@@ -64,7 +64,8 @@
                             <property name="typeName" value="org.apache.ignite.platform.PlatformComputeJavaBinarizable"/>
                         </bean>
                         <bean class="org.apache.ignite.binary.BinaryTypeConfiguration">
-                            <property name="typeName" value="org.apache.ignite.platform.PlatformComputeEnum"/>
+                            <property name="typeName" value="org.apache.ignite.platform.PlatformComputeEnum" />
+                            <property name="enum" value="true" />
                         </bean>
                     </list>
                 </property>
@@ -86,10 +87,5 @@
                 </property>
             </bean>
         </property>
-
-        <!-- Binary marshaller configuration -->
-        <property name="marshaller">
-            <bean class="org.apache.ignite.marshaller.portable.BinaryMarshaller"/>
-        </property>
     </bean>
 </beans>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/marshaller-explicit.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/marshaller-explicit.xml
index 2f7d746..366ac13 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/marshaller-explicit.xml
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/marshaller-explicit.xml
@@ -32,7 +32,7 @@
         </property>
 
         <property name="marshaller">
-            <bean class="org.apache.ignite.marshaller.portable.BinaryMarshaller"/>
+            <bean class="org.apache.ignite.internal.portable.BinaryMarshaller"/>
         </property>
 
         <property name="discoverySpi">
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/native-client-test-cache-store.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/native-client-test-cache-store.xml
index b414a91..25a1d16 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/native-client-test-cache-store.xml
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/native-client-test-cache-store.xml
@@ -41,6 +41,7 @@
                     <property name="atomicityMode" value="TRANSACTIONAL"/>
                     <property name="writeThrough" value="true"/>
                     <property name="readThrough" value="true"/>
+                    <property name="keepBinaryInStore" value="true"/>
 
                     <property name="cacheStoreFactory">
                         <bean class="org.apache.ignite.platform.dotnet.PlatformDotNetCacheStoreFactory">
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
index 087f886..bcf6baa6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
@@ -102,13 +102,16 @@
                     if (example.NeedsTestDll)
                         args.Add(" -assembly=" + typeof(AverageSalaryJob).Assembly.Location);
 
-                    // ReSharper disable once UnusedVariable
                     var proc = new IgniteProcess(args.ToArray());
 
                     Assert.IsTrue(ignite.WaitTopology(i + 2, 30000));
+                    Assert.IsTrue(proc.Alive);
                 }
 
                 Ignition.ClientMode = clientMode;
+
+                // Run twice to catch issues with standalone node state
+                example.Run();
                 example.Run();
             }
         }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
index 1797337..973381c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServiceProxyTest.cs
@@ -48,7 +48,7 @@
         });
 
         /** */
-        protected readonly IIgniteBinary IgniteBinary;
+        protected readonly IBinary Binary;
 
         /** */
         private readonly PlatformMemoryManager _memory = new PlatformMemoryManager(1024);
@@ -64,7 +64,7 @@
         /// </summary>
         public ServiceProxyTest()
         {
-            IgniteBinary = new IgniteBinary(_marsh);
+            Binary = new Binary(_marsh);
         }
 
         /// <summary>
@@ -243,7 +243,7 @@
         /// </summary>
         protected T GetProxy<T>()
         {
-            _svc = new TestIgniteService(IgniteBinary);
+            _svc = new TestIgniteService(Binary);
 
             var prx = new ServiceProxy<T>(InvokeProxyMethod).GetTransparentProxy();
 
@@ -439,15 +439,15 @@
         private class TestIgniteService : ITestIgniteService, ITestIgniteServiceAmbiguity
         {
             /** */
-            private readonly IIgniteBinary _igniteBinary;
+            private readonly IBinary _binary;
 
             /// <summary>
             /// Initializes a new instance of the <see cref="TestIgniteService"/> class.
             /// </summary>
-            /// <param name="igniteBinary">Binary.</param>
-            public TestIgniteService(IIgniteBinary igniteBinary)
+            /// <param name="binary">Binary.</param>
+            public TestIgniteService(IBinary binary)
             {
-                _igniteBinary = igniteBinary;
+                _binary = binary;
             }
 
             /** <inheritdoc /> */
@@ -534,13 +534,13 @@
             /** <inheritdoc /> */
             public IBinaryObject BinarizableResultMethod(int arg1, TestBinarizableClass arg2)
             {
-                return _igniteBinary.ToBinary<IBinaryObject>(arg2);
+                return _binary.ToBinary<IBinaryObject>(arg2);
             }
 
             /** <inheritdoc /> */
             public IBinaryObject BinarizableArgAndResultMethod(int arg1, IBinaryObject arg2)
             {
-                return _igniteBinary.ToBinary<IBinaryObject>(arg2.Deserialize<TestBinarizableClass>());
+                return _binary.ToBinary<IBinaryObject>(arg2.Deserialize<TestBinarizableClass>());
             }
 
             /** <inheritdoc /> */
@@ -703,7 +703,7 @@
             var prx = GetProxy();
 
             var obj = new TestBinarizableClass { Prop = "PropValue" };
-            var portObj = IgniteBinary.ToBinary<IBinaryObject>(obj);
+            var portObj = Binary.ToBinary<IBinaryObject>(obj);
 
             var result = prx.BinarizableArgMethod(1, portObj);
 
@@ -731,7 +731,7 @@
             var prx = GetProxy();
             
             var obj = new TestBinarizableClass { Prop = "PropValue" };
-            var portObj = IgniteBinary.ToBinary<IBinaryObject>(obj);
+            var portObj = Binary.ToBinary<IBinaryObject>(obj);
 
             var result = prx.BinarizableArgAndResultMethod(1, portObj);
 
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index ae10159..2c7d787 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -134,6 +134,7 @@
     <Compile Include="IgniteConfiguration.cs" />
     <Compile Include="Ignition.cs" />
     <Compile Include="IIgnite.cs" />
+    <Compile Include="Impl\Binary\BinaryEnum.cs" />
     <Compile Include="Impl\Cache\CacheAffinityImpl.cs" />
     <Compile Include="Impl\Cache\CacheEntry.cs" />
     <Compile Include="Impl\Cache\CacheEntryFilterHolder.cs" />
@@ -266,7 +267,7 @@
     <Compile Include="Impl\Binary\BinaryReader.cs" />
     <Compile Include="Impl\Binary\BinaryReflectiveActions.cs" />
     <Compile Include="Impl\Binary\BinaryReflectiveSerializer.cs" />
-    <Compile Include="Impl\Binary\IgniteBinary.cs" />
+    <Compile Include="Impl\Binary\Binary.cs" />
     <Compile Include="Impl\Binary\Structure\BinaryStructureTracker.cs" />
     <Compile Include="Impl\Binary\BinarySurrogateTypeDescriptor.cs" />
     <Compile Include="Impl\Binary\BinarySystemHandlers.cs" />
@@ -316,7 +317,7 @@
     <Compile Include="Binary\IBinaryRawReader.cs" />
     <Compile Include="Binary\IBinaryRawWriter.cs" />
     <Compile Include="Binary\IBinaryReader.cs" />
-    <Compile Include="Binary\IIgniteBinary.cs" />
+    <Compile Include="Binary\IBinary.cs" />
     <Compile Include="Binary\IBinarySerializer.cs" />
     <Compile Include="Binary\IBinaryWriter.cs" />
     <Compile Include="Binary\BinaryConfiguration.cs" />
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
index 967aa52..99f8572 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryTypeConfiguration.cs
@@ -48,6 +48,7 @@
         public BinaryTypeConfiguration(Type type)
         {
             TypeName = type.AssemblyQualifiedName;
+            IsEnum = type.IsEnum;
         }
 
         /// <summary>
@@ -62,6 +63,7 @@
             Serializer = cfg.Serializer;
             TypeName = cfg.TypeName;
             KeepDeserialized = cfg.KeepDeserialized;
+            IsEnum = cfg.IsEnum;
         }
 
         /// <summary>
@@ -101,6 +103,11 @@
         public bool? KeepDeserialized { get; set; }
 
         /// <summary>
+        /// Gets or sets a value indicating whether this instance describes an enum type.
+        /// </summary>
+        public bool IsEnum { get; set; }
+
+        /// <summary>
         /// Returns a string that represents the current object.
         /// </summary>
         /// <returns>
@@ -108,9 +115,12 @@
         /// </returns>
         public override string ToString()
         {
-            return typeof (BinaryTypeConfiguration).Name + " [TypeName=" + TypeName +
-                   ", NameMapper=" + NameMapper + ", IdMapper=" + IdMapper + ", Serializer=" + Serializer +
-                   ", AffinityKeyFieldName=" + AffinityKeyFieldName + ']';
+            return
+                string.Format(
+                    "{0} [TypeName={1}, NameMapper={2}, IdMapper={3}, Serializer={4}, AffinityKeyFieldName={5}, " +
+                    "KeepDeserialized={6}, IsEnum={7}]",
+                    typeof (BinaryTypeConfiguration).Name, TypeName, NameMapper, IdMapper, Serializer,
+                    AffinityKeyFieldName, KeepDeserialized, IsEnum);
         }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IIgniteBinary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs
similarity index 86%
rename from modules/platforms/dotnet/Apache.Ignite.Core/Binary/IIgniteBinary.cs
rename to modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs
index 25ea981..a0fc17f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IIgniteBinary.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinary.cs
@@ -52,7 +52,7 @@
     ///     </item>
     /// </list>
     /// </summary>
-    public interface IIgniteBinary
+    public interface IBinary
     {
         /// <summary>
         /// Converts provided object to binary form.
@@ -116,5 +116,21 @@
         /// </summary>
         /// <returns>Metadata.</returns>
         IBinaryType GetBinaryType(Type type);
+
+        /// <summary>
+        /// Converts enum to a binary form.
+        /// </summary>
+        /// <param name="typeName">Enum type name.</param>
+        /// <param name="value">Enum int value.</param>
+        /// <returns>Binary representation of the specified enum value.</returns>
+        IBinaryObject BuildEnum(string typeName, int value);
+
+        /// <summary>
+        /// Converts enum to a binary form.
+        /// </summary>
+        /// <param name="type">Enum type.</param>
+        /// <param name="value">Enum int value.</param>
+        /// <returns>Binary representation of the specified enum value.</returns>
+        IBinaryObject BuildEnum(Type type, int value);
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs
index bd60e28..c5aa80e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryObject.cs
@@ -25,14 +25,6 @@
     public interface IBinaryObject
     {
         /// <summary>
-        /// Gets binary object type ID.
-        /// </summary>
-        /// <value>
-        /// Type ID.
-        /// </value>
-        int TypeId { get; }
-
-        /// <summary>
         /// Gets object metadata.
         /// </summary>
         /// <returns>Metadata.</returns>
@@ -50,11 +42,26 @@
         TF GetField<TF>(string fieldName);
 
         /// <summary>
+        /// Determines whether the field with specified name exists in this instance.
+        /// </summary>
+        /// <param name="fieldName">Name of the field.</param>
+        /// <returns>True if there is a field with specified name; false otherwise.</returns>
+        bool HasField(string fieldName);
+
+        /// <summary>
         /// Gets fully deserialized instance of binary object.
         /// </summary>
         /// <returns>
         /// Fully deserialized instance of binary object.
         /// </returns>
         T Deserialize<T>();
+
+        /// <summary>
+        /// Gets the value of underlying enum in int form.
+        /// </summary>
+        /// <value>
+        /// The value of underlying enum in int form.
+        /// </value>
+        int EnumValue { get; }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs
index 7b34e07..bec863f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/IBinaryType.cs
@@ -48,5 +48,18 @@
         /// </summary>
         /// <returns>Affinity key field name or null in case it is not provided.</returns>
         string AffinityKeyFieldName { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether this type represents an enum.
+        /// </summary>
+        /// <value>   
+        /// <c>true</c> if this instance represents an enum; otherwise, <c>false</c>.
+        /// </value>
+        bool IsEnum { get; }
+
+        /// <summary>
+        /// Gets the type identifier.
+        /// </summary>
+        int TypeId { get; }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
index b9d9555..08e5f6b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs
@@ -111,11 +111,11 @@
         IDataStreamer<TK, TV> GetDataStreamer<TK, TV>(string cacheName);
 
         /// <summary>
-        /// Gets an instance of <see cref="IIgniteBinary"/> interface.
+        /// Gets an instance of <see cref="IBinary"/> interface.
         /// </summary>
-        /// <returns>Instance of <see cref="IIgniteBinary"/> interface</returns>
+        /// <returns>Instance of <see cref="IBinary"/> interface</returns>
         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Semantics.")]
-        IIgniteBinary GetBinary();
+        IBinary GetBinary();
 
         /// <summary>
         /// Gets affinity service to provide information about data partitioning and distribution.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IgniteBinary.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
similarity index 86%
rename from modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IgniteBinary.cs
rename to modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
index ecc6807..43a4bb8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IgniteBinary.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Binary.cs
@@ -23,12 +23,13 @@
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Binary.Metadata;
     using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
     /// Binary implementation.
     /// </summary>
-    internal class IgniteBinary : IIgniteBinary
+    internal class Binary : IBinary
     {
         /** Owning grid. */
         private readonly Marshaller _marsh;
@@ -37,7 +38,7 @@
         /// Constructor.
         /// </summary>
         /// <param name="marsh">Marshaller.</param>
-        internal IgniteBinary(Marshaller marsh)
+        internal Binary(Marshaller marsh)
         {
             _marsh = marsh;
         }
@@ -146,6 +147,29 @@
             return desc == null ? null : Marshaller.GetBinaryType(desc.TypeId);
         }
 
+        /** <inheritDoc /> */
+        public IBinaryObject BuildEnum(string typeName, int value)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(typeName, "typeName");
+
+            var desc = Marshaller.GetDescriptor(typeName);
+
+            IgniteArgumentCheck.Ensure(desc.IsEnum, "typeName", "Type should be an Enum.");
+
+            _marsh.PutBinaryType(desc);
+
+            return new BinaryEnum(GetTypeId(typeName), value, Marshaller);
+        }
+
+        /** <inheritDoc /> */
+        public IBinaryObject BuildEnum(Type type, int value)
+        {
+            IgniteArgumentCheck.NotNull(type, "type");
+            IgniteArgumentCheck.Ensure(type.IsEnum, "type", "Type should be an Enum.");
+
+            return BuildEnum(type.Name, value);
+        }
+
         /// <summary>
         /// Marshaller.
         /// </summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs
new file mode 100644
index 0000000..97f44b0
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryEnum.cs
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Binary
+{
+    using System;
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Binary;
+
+    /// <summary>
+    /// Represents a typed enum in binary form.
+    /// </summary>
+    internal class BinaryEnum : IBinaryObject, IEquatable<BinaryEnum>
+    {
+        /** Type id. */
+        private readonly int _typeId;
+
+        /** Value. */
+        private readonly int _enumValue;
+
+        /** Marshaller. */
+        private readonly Marshaller _marsh;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BinaryEnum" /> class.
+        /// </summary>
+        /// <param name="typeId">The type identifier.</param>
+        /// <param name="enumValue">The value.</param>
+        /// <param name="marsh">The marshaller.</param>
+        public BinaryEnum(int typeId, int enumValue, Marshaller marsh)
+        {
+            Debug.Assert(marsh != null);
+
+            _typeId = typeId;
+            _enumValue = enumValue;
+            _marsh = marsh;
+        }
+
+        /** <inheritdoc /> */
+        public int TypeId
+        {
+            get { return _typeId; }
+        }
+
+        /** <inheritdoc /> */
+        public IBinaryType GetBinaryType()
+        {
+            return _marsh.GetBinaryType(_typeId);
+        }
+
+        /** <inheritdoc /> */
+        public TF GetField<TF>(string fieldName)
+        {
+            return default(TF);
+        }
+
+        /** <inheritdoc /> */
+        public bool HasField(string fieldName)
+        {
+            return false;
+        }
+
+        /** <inheritdoc /> */
+        public T Deserialize<T>()
+        {
+            return BinaryUtils.GetEnumValue<T>(_enumValue, _typeId, _marsh);
+        }
+
+        /** <inheritdoc /> */
+        public int EnumValue
+        {
+            get { return _enumValue; }
+        }
+
+        /** <inheritdoc /> */
+        public bool Equals(BinaryEnum other)
+        {
+            if (ReferenceEquals(null, other))
+                return false;
+
+            if (ReferenceEquals(this, other))
+                return true;
+
+            return _typeId == other._typeId && _enumValue == other._enumValue;
+        }
+
+        /** <inheritdoc /> */
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj))
+                return false;
+
+            if (ReferenceEquals(this, obj))
+                return true;
+
+            if (obj.GetType() != GetType())
+                return false;
+
+            return Equals((BinaryEnum) obj);
+        }
+
+        /** <inheritdoc /> */
+        public override int GetHashCode()
+        {
+            return _enumValue.GetHashCode();
+        }
+
+        /** <inheritdoc /> */
+        public static bool operator ==(BinaryEnum left, BinaryEnum right)
+        {
+            return Equals(left, right);
+        }
+
+        /** <inheritdoc /> */
+        public static bool operator !=(BinaryEnum left, BinaryEnum right)
+        {
+            return !Equals(left, right);
+        }
+    }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
index 9649595..3d2b34d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryFullTypeDescriptor.cs
@@ -63,6 +63,9 @@
         /** Type schema. */
         private readonly BinaryObjectSchema _schema = new BinaryObjectSchema();
 
+        /** Enum flag. */
+        private bool _isEnum;
+
         /// <summary>
         /// Constructor.
         /// </summary>
@@ -75,6 +78,7 @@
         /// <param name="serializer">Serializer.</param>
         /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param>
         /// <param name="affKeyFieldName">Affinity field key name.</param>
+        /// <param name="isEnum">Enum flag.</param>
         public BinaryFullTypeDescriptor(
             Type type, 
             int typeId, 
@@ -84,7 +88,8 @@
             IBinaryIdMapper idMapper, 
             IBinarySerializer serializer, 
             bool keepDeserialized, 
-            string affKeyFieldName)
+            string affKeyFieldName,
+            bool isEnum)
         {
             _type = type;
             _typeId = typeId;
@@ -95,6 +100,7 @@
             _serializer = serializer;
             _keepDeserialized = keepDeserialized;
             _affKeyFieldName = affKeyFieldName;
+            _isEnum = isEnum;
         }
 
         /// <summary>
@@ -169,6 +175,12 @@
             get { return _affKeyFieldName; }
         }
 
+        /** <inheritdoc/> */
+        public bool IsEnum
+        {
+            get { return _isEnum; }
+        }
+
         /** <inheritDoc /> */
         public BinaryStructure WriterTypeStructure
         {
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
index fd60da7..90607dd 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObject.cs
@@ -17,14 +17,17 @@
 
 namespace Apache.Ignite.Core.Impl.Binary
 {
+    using System;
     using System.Collections;
     using System.Collections.Generic;
+    using System.Diagnostics;
     using System.IO;
     using System.Runtime.CompilerServices;
     using System.Text;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Common;
     using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
     /// Binary object.
@@ -61,6 +64,10 @@
         /// <param name="header">The header.</param>
         public BinaryObject(Marshaller marsh, byte[] data, int offset, BinaryObjectHeader header)
         {
+            Debug.Assert(marsh != null);
+            Debug.Assert(data != null);
+            Debug.Assert(offset >= 0 && offset < data.Length);
+
             _marsh = marsh;
 
             _data = data;
@@ -78,11 +85,23 @@
         /** <inheritdoc /> */
         public T GetField<T>(string fieldName)
         {
+            IgniteArgumentCheck.NotNullOrEmpty(fieldName, "fieldName");
+
             int pos;
 
             return TryGetFieldPosition(fieldName, out pos) ? GetField<T>(pos, null) : default(T);
         }
 
+        /** <inheritdoc /> */
+        public bool HasField(string fieldName)
+        {
+            IgniteArgumentCheck.NotNullOrEmpty(fieldName, "fieldName");
+
+            int pos;
+
+            return TryGetFieldPosition(fieldName, out pos);
+        }
+
         /// <summary>
         /// Gets field value on the given object.
         /// </summary>
@@ -104,6 +123,16 @@
             return Deserialize<T>(BinaryMode.Deserialize);
         }
 
+        /** <inheritdoc /> */
+        public int EnumValue
+        {
+            get
+            {
+                throw new NotSupportedException("IBinaryObject.Value is only supported for enums. " +
+                    "Check IBinaryObject.IsEnum property before accessing Value.");
+            }
+        }
+
         /// <summary>
         /// Internal deserialization routine.
         /// </summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
index 97cc381..7ef6259 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryObjectBuilder.cs
@@ -37,7 +37,7 @@
             new Dictionary<int, BinaryBuilderField>();
         
         /** Binary. */
-        private readonly IgniteBinary _igniteBinary;
+        private readonly Binary _binary;
 
         /** */
         private readonly BinaryObjectBuilder _parent;
@@ -79,18 +79,18 @@
         /// <summary>
         /// Constructor.
         /// </summary>
-        /// <param name="igniteBinary">Binary.</param>
+        /// <param name="binary">Binary.</param>
         /// <param name="parent">Parent builder.</param>
         /// <param name="obj">Initial binary object.</param>
         /// <param name="desc">Type descriptor.</param>
-        public BinaryObjectBuilder(IgniteBinary igniteBinary, BinaryObjectBuilder parent, 
+        public BinaryObjectBuilder(Binary binary, BinaryObjectBuilder parent, 
             BinaryObject obj, IBinaryTypeDescriptor desc)
         {
-            Debug.Assert(igniteBinary != null);
+            Debug.Assert(binary != null);
             Debug.Assert(obj != null);
             Debug.Assert(desc != null);
 
-            _igniteBinary = igniteBinary;
+            _binary = binary;
             _parent = parent ?? this;
             _obj = obj;
             _desc = desc;
@@ -361,7 +361,7 @@
 
             BinaryHeapStream outStream = new BinaryHeapStream(estimatedCapacity);
 
-            BinaryWriter writer = _igniteBinary.Marshaller.StartMarshal(outStream);
+            BinaryWriter writer = _binary.Marshaller.StartMarshal(outStream);
 
             writer.SetBuilder(this);
 
@@ -374,10 +374,10 @@
                 writer.Write(this);
                 
                 // Process metadata.
-                _igniteBinary.Marshaller.FinishMarshal(writer);
+                _binary.Marshaller.FinishMarshal(writer);
 
                 // Create binary object once metadata is processed.
-                return new BinaryObject(_igniteBinary.Marshaller, outStream.InternalArray, 0, 
+                return new BinaryObject(_binary.Marshaller, outStream.InternalArray, 0, 
                     BinaryObjectHeader.Read(outStream, 0));
             }
             finally
@@ -394,9 +394,9 @@
         /// <returns>Child builder.</returns>
         public BinaryObjectBuilder Child(BinaryObject obj)
         {
-            var desc = _igniteBinary.Marshaller.GetDescriptor(true, obj.TypeId);
+            var desc = _binary.Marshaller.GetDescriptor(true, obj.TypeId);
 
-            return new BinaryObjectBuilder(_igniteBinary, null, obj, desc);
+            return new BinaryObjectBuilder(_binary, null, obj, desc);
         }
         
         /// <summary>
@@ -436,7 +436,7 @@
 
             var hdr = _obj.Data[pos];
 
-            var field = new BinaryBuilderField(typeof(T), val, hdr, GetWriteAction(hdr));
+            var field = new BinaryBuilderField(typeof(T), val, hdr, GetWriteAction(hdr, pos));
             
             _parent._cache[pos] = field;
 
@@ -447,8 +447,9 @@
         /// Gets the write action by header.
         /// </summary>
         /// <param name="header">The header.</param>
+        /// <param name="pos">Position.</param>
         /// <returns>Write action.</returns>
-        private static Action<BinaryWriter, object> GetWriteAction(byte header)
+        private Action<BinaryWriter, object> GetWriteAction(byte header, int pos)
         {
             // We need special actions for all cases where SetField(X) produces different result from SetSpecialField(X)
             // Arrays, Collections, Dates
@@ -466,9 +467,20 @@
 
                 case BinaryUtils.TypeArrayTimestamp:
                     return WriteTimestampArrayAction;
-            }
 
-            return null;
+                case BinaryUtils.TypeArrayEnum:
+                    using (var stream = new BinaryHeapStream(_obj.Data))
+                    {
+                        stream.Seek(pos, SeekOrigin.Begin + 1);
+
+                        var elementTypeId = stream.ReadInt();
+
+                        return (w, o) => w.WriteEnumArrayInternal((Array) o, elementTypeId);
+                    }
+
+                default:
+                    return null;
+            }
         }
 
         /// <summary>
@@ -510,7 +522,7 @@
             try
             {
                 // Prepare fields.
-                IBinaryTypeHandler metaHnd = _igniteBinary.Marshaller.GetBinaryTypeHandler(desc);
+                IBinaryTypeHandler metaHnd = _binary.Marshaller.GetBinaryTypeHandler(desc);
 
                 IDictionary<int, BinaryBuilderField> vals0;
 
@@ -546,7 +558,7 @@
                     IDictionary<string, int> meta = metaHnd.OnObjectWriteFinished();
 
                     if (meta != null)
-                        _parent._ctx.Writer.SaveMetadata(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, meta);
+                        _parent._ctx.Writer.SaveMetadata(desc, meta);
                 }
             }
             finally
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
index 9aeb908..7b887a9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
@@ -399,13 +399,34 @@
         /** <inheritdoc /> */
         public T ReadEnum<T>(string fieldName)
         {
-            return ReadField(fieldName, BinaryUtils.ReadEnum<T>, BinaryUtils.TypeEnum);
+            return SeekField(fieldName) ? ReadEnum<T>() : default(T);
         }
 
         /** <inheritdoc /> */
         public T ReadEnum<T>()
         {
-            return Read(BinaryUtils.ReadEnum<T>, BinaryUtils.TypeEnum);
+            var hdr = ReadByte();
+
+            switch (hdr)
+            {
+                case BinaryUtils.HdrNull:
+                    return default(T);
+
+                case BinaryUtils.TypeEnum:
+                    // Never read enums in binary mode when reading a field (we do not support half-binary objects)
+                    return ReadEnum0<T>(this, false);  
+
+                case BinaryUtils.HdrFull:
+                    // Unregistered enum written as serializable
+                    Stream.Seek(-1, SeekOrigin.Current);
+
+                    return ReadObject<T>(); 
+
+                default:
+                    throw new BinaryObjectException(
+                        string.Format("Invalid header on enum deserialization. Expected: {0} or {1} but was: {2}",
+                            BinaryUtils.TypeEnum, BinaryUtils.HdrFull, hdr));
+            }
         }
 
         /** <inheritdoc /> */
@@ -560,14 +581,15 @@
                     res = ReadBinaryObject<T>(doDetach);
 
                     return true;
+
+                case BinaryUtils.TypeEnum:
+                    res = ReadEnum0<T>(this, _mode != BinaryMode.Deserialize);
+
+                    return true;
             }
 
-            if (BinaryUtils.IsPredefinedType(hdr))
-            {
-                res = BinarySystemHandlers.ReadSystemType<T>(hdr, this);
-
+            if (BinarySystemHandlers.TryReadSystemType(hdr, this, out res))
                 return true;
-            }
 
             throw new BinaryObjectException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']');
         }
@@ -961,5 +983,20 @@
         {
             return IsNotNullHeader(expHdr) ? readFunc(Stream) : default(T);
         }
+
+        /// <summary>
+        /// Reads the enum.
+        /// </summary>
+        private static T ReadEnum0<T>(BinaryReader reader, bool keepBinary)
+        {
+            var enumType = reader.ReadInt();
+
+            var enumValue = reader.ReadInt();
+
+            if (!keepBinary)
+                return BinaryUtils.GetEnumValue<T>(enumValue, enumType, reader.Marshaller);
+
+            return TypeCaster<T>.Cast(new BinaryEnum(enumType, enumValue, reader.Marshaller));
+        }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
index 247b40d..04028b5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs
@@ -124,6 +124,12 @@
             get { return null; }
         }
 
+        /** <inheritdoc/> */
+        public bool IsEnum
+        {
+            get { return false; }
+        }
+
         /** <inheritDoc /> */
         public BinaryStructure WriterTypeStructure
         {
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
index b49c29d..0af1e82 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
@@ -22,6 +22,7 @@
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
+    using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Common;
 
@@ -166,7 +167,6 @@
             ReadHandlers[BinaryUtils.TypeMapEntry] = new BinarySystemReader(ReadMapEntry);
             
             // 16. Enum.
-            ReadHandlers[BinaryUtils.TypeEnum] = new BinarySystemReader<int>(BinaryUtils.ReadEnum<int>);
             ReadHandlers[BinaryUtils.TypeArrayEnum] = new BinarySystemReader(ReadEnumArray);
         }
 
@@ -212,6 +212,8 @@
                 return WriteGuid;
             if (type == typeof (BinaryObject))
                 return WriteBinary;
+            if (type == typeof (BinaryEnum))
+                return WriteBinaryEnum;
             if (type == typeof (ArrayList))
                 return WriteArrayList;
             if (type == typeof(Hashtable))
@@ -257,11 +259,11 @@
                 if (elemType == typeof(Guid?))
                     return WriteGuidArray;
                 // Enums.
-                if (elemType.IsEnum)
+                if (elemType.IsEnum || elemType == typeof(BinaryEnum))
                     return WriteEnumArray;
                 
                 // Object array.
-                if (elemType == typeof (object))
+                if (elemType == typeof (object) || elemType == typeof(IBinaryObject) || elemType == typeof(BinaryObject))
                     return WriteArray;
             }
 
@@ -329,13 +331,18 @@
         /// <summary>
         /// Reads an object of predefined type.
         /// </summary>
-        public static T ReadSystemType<T>(byte typeId, BinaryReader ctx)
+        public static bool TryReadSystemType<T>(byte typeId, BinaryReader ctx, out T res)
         {
             var handler = ReadHandlers[typeId];
 
-            Debug.Assert(handler != null, "Cannot find predefined read handler: " + typeId);
-            
-            return handler.Read<T>(ctx);
+            if (handler == null)
+            {
+                res = default(T);
+                return false;
+            }
+
+            res = handler.Read<T>(ctx);
+            return true;
         }
         
         /// <summary>
@@ -629,9 +636,20 @@
         /// </summary>
         private static void WriteEnum(BinaryWriter ctx, object obj)
         {
+            ctx.WriteEnum(obj);
+        }
+
+        /// <summary>
+        /// Write enum.
+        /// </summary>
+        private static void WriteBinaryEnum(BinaryWriter ctx, object obj)
+        {
+            var binEnum = (BinaryEnum) obj;
+
             ctx.Stream.WriteByte(BinaryUtils.TypeEnum);
 
-            BinaryUtils.WriteEnum(ctx, obj);
+            ctx.WriteInt(binEnum.TypeId);
+            ctx.WriteInt(binEnum.EnumValue);
         }
 
         /// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
index 1aed03f..1917f01 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -23,7 +23,9 @@
     using System.Collections.Generic;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
+    using System.Globalization;
     using System.IO;
+    using System.Linq;
     using System.Reflection;
     using System.Runtime.InteropServices;
     using System.Text;
@@ -1318,25 +1320,29 @@
             }
 
             throw new BinaryObjectException("Only Int32 underlying type is supported for enums: " +
-                enumType.Name);
+                                            enumType.Name);
         }
 
         /// <summary>
-        /// Read enum.
+        /// Gets the enum value by type id and int representation.
         /// </summary>
-        /// <param name="stream">Stream.</param>
-        /// <returns>Enumeration.</returns>
-        public static T ReadEnum<T>(IBinaryStream stream)
+        /// <typeparam name="T">Result type.</typeparam>
+        /// <param name="value">The value.</param>
+        /// <param name="typeId">The type identifier.</param>
+        /// <param name="marsh">The marshaller.</param>
+        /// <returns>value in form of enum, if typeId is known; value in for of int, if typeId is -1.</returns>
+        public static T GetEnumValue<T>(int value, int typeId, Marshaller marsh)
         {
-            if (!typeof(T).IsEnum || Enum.GetUnderlyingType(typeof(T)) == TypInt)
-            {
-                stream.ReadInt();
+            if (typeId == ObjTypeId)
+                return TypeCaster<T>.Cast(value);
 
-                return TypeCaster<T>.Cast(stream.ReadInt());
-            }
+            // All enums are user types
+            var desc = marsh.GetDescriptor(true, typeId);
 
-            throw new BinaryObjectException("Only Int32 underlying type is supported for enums: " +
-                                        typeof (T).Name);
+            if (desc == null || desc.Type == null)
+                throw new BinaryObjectException("Unknown enum type id: " + typeId);
+
+            return (T)Enum.ToObject(desc.Type, value);
         }
 
         /**
@@ -1387,52 +1393,6 @@
         }
 
         /**
-         * <summary>Check whether this is predefined type.</summary>
-         * <param name="hdr">Header.</param>
-         * <returns>True is this is one of predefined types with special semantics.</returns>
-         */
-        public static bool IsPredefinedType(byte hdr)
-        {
-            switch (hdr)
-            {
-                case TypeByte:
-                case TypeShort:
-                case TypeInt:
-                case TypeLong:
-                case TypeFloat:
-                case TypeDouble:
-                case TypeChar:
-                case TypeBool:
-                case TypeDecimal:
-                case TypeString:
-                case TypeGuid:
-                case TypeTimestamp:
-                case TypeEnum:
-                case TypeArrayByte:
-                case TypeArrayShort:
-                case TypeArrayInt:
-                case TypeArrayLong:
-                case TypeArrayFloat:
-                case TypeArrayDouble:
-                case TypeArrayChar:
-                case TypeArrayBool:
-                case TypeArrayDecimal:
-                case TypeArrayString:
-                case TypeArrayGuid:
-                case TypeArrayTimestamp:
-                case TypeArrayEnum:
-                case TypeArray:
-                case TypeCollection:
-                case TypeDictionary:
-                case TypeMapEntry:
-                case TypeBinary:
-                    return true;
-                default:
-                    return false;
-            }
-        }
-
-        /**
          * <summary>Convert type name.</summary>
          * <param name="typeName">Type name.</param>
          * <param name="converter">Converter.</param>
@@ -1534,6 +1494,23 @@
             return id;
         }
 
+        /// <summary>
+        /// Gets the name of the type.
+        /// </summary>
+        /// <param name="type">The type.</param>
+        /// <returns>
+        /// Simple type name for non-generic types; simple type name with appended generic arguments for generic types.
+        /// </returns>
+        public static string GetTypeName(Type type)
+        {
+            if (!type.IsGenericType)
+                return type.Name;
+
+            var args = type.GetGenericArguments().Select(GetTypeName).Aggregate((x, y) => x + "," + y);
+
+            return string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", type.Name, args);
+        }
+
         /**
          * <summary>Resolve field ID.</summary>
          * <param name="typeId">Type ID.</param>
@@ -1732,7 +1709,8 @@
                             IdMapper = CreateInstance<IBinaryIdMapper>(reader),
                             Serializer = CreateInstance<IBinarySerializer>(reader),
                             AffinityKeyFieldName = reader.ReadString(),
-                            KeepDeserialized = reader.ReadObject<bool?>()
+                            KeepDeserialized = reader.ReadObject<bool?>(),
+                            IsEnum = reader.ReadBoolean()
                         });
                     }
                 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index c00dad6..189cd50 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -20,12 +20,12 @@
     using System;
     using System.Collections;
     using System.Collections.Generic;
+    using System.Diagnostics;
     using System.IO;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Binary.Metadata;
     using Apache.Ignite.Core.Impl.Binary.Structure;
-    using Apache.Ignite.Core.Impl.Common;
 
     /// <summary>
     /// Binary writer implementation.
@@ -45,7 +45,7 @@
         private BinaryHandleDictionary<object, long> _hnds;
 
         /** Metadatas collected during this write session. */
-        private IDictionary<int, IBinaryType> _metas;
+        private IDictionary<int, BinaryType> _metas;
 
         /** Current type ID. */
         private int _curTypeId;
@@ -803,8 +803,28 @@
         /// <param name="val">Enum value.</param>
         public void WriteEnum<T>(T val)
         {
-            _stream.WriteByte(BinaryUtils.TypeEnum);
-            BinaryUtils.WriteEnum(this, val);
+            if (val == null)
+                WriteNullField();
+            else
+            {
+                var desc = _marsh.GetDescriptor(val.GetType());
+
+                if (desc != null)
+                {
+                    var metaHnd = _marsh.GetBinaryTypeHandler(desc);
+
+                    _stream.WriteByte(BinaryUtils.TypeEnum);
+
+                    BinaryUtils.WriteEnum(this, val);
+
+                    SaveMetadata(desc, metaHnd.OnObjectWriteFinished());
+                }
+                else
+                {
+                    // Unregistered enum, write as serializable
+                    Write(new SerializableObjectHolder(val));
+                }
+            }
         }
 
         /// <summary>
@@ -817,10 +837,7 @@
         {
             WriteFieldId(fieldName, BinaryUtils.TypeArrayEnum);
 
-            if (val == null)
-                WriteNullField();
-            else
-                WriteEnumArray0(val);
+            WriteEnumArray(val);
         }
 
         /// <summary>
@@ -830,24 +847,26 @@
         /// <param name="val">Enum array.</param>
         public void WriteEnumArray<T>(T[] val)
         {
-            if (val == null)
-                WriteNullRawField();
-            else
-                WriteEnumArray0(val);
+            WriteEnumArrayInternal(val, null);
         }
 
         /// <summary>
         /// Writes the enum array.
         /// </summary>
         /// <param name="val">The value.</param>
-        private void WriteEnumArray0<T>(T[] val)
+        /// <param name="elementTypeId">The element type id.</param>
+        public void WriteEnumArrayInternal(Array val, int? elementTypeId)
         {
-            _stream.WriteByte(BinaryUtils.TypeArrayEnum);
+            if (val == null)
+                WriteNullField();
+            else
+            {
+                _stream.WriteByte(BinaryUtils.TypeArrayEnum);
 
-            // typeof(T) can yield wrong results (string[] is object[], for example)
-            var elementType = val.GetType().GetElementType();  
+                var elTypeId = elementTypeId ?? BinaryUtils.GetEnumTypeId(val.GetType().GetElementType(), Marshaller);
 
-            BinaryUtils.WriteArray(val, this, BinaryUtils.GetEnumTypeId(elementType, Marshaller));
+                BinaryUtils.WriteArray(val, this, elTypeId);
+            }
         }
 
         /// <summary>
@@ -1051,12 +1070,20 @@
                 return;
             }
 
+            // Handle enums.
+            if (type.IsEnum)
+            {
+                WriteEnum(obj);
+
+                return;
+            }
+
             // Handle special case for builder.
             if (WriteBuilderSpecials(obj))
                 return;
 
             // Suppose that we faced normal object and perform descriptor lookup.
-            IBinaryTypeDescriptor desc = type.IsEnum ? null : _marsh.GetDescriptor(type);
+            IBinaryTypeDescriptor desc = _marsh.GetDescriptor(type);
 
             if (desc != null)
             {
@@ -1356,9 +1383,9 @@
         /// Gets collected metadatas.
         /// </summary>
         /// <returns>Collected metadatas (if any).</returns>
-        internal IDictionary<int, IBinaryType> GetBinaryTypes()
+        internal ICollection<BinaryType> GetBinaryTypes()
         {
-            return _metas;
+            return _metas == null ? null : _metas.Values;
         }
 
         /// <summary>
@@ -1399,37 +1426,38 @@
         /// <summary>
         /// Saves metadata for this session.
         /// </summary>
-        /// <param name="typeId">Type ID.</param>
-        /// <param name="typeName">Type name.</param>
-        /// <param name="affKeyFieldName">Affinity key field name.</param>
+        /// <param name="desc">The descriptor.</param>
         /// <param name="fields">Fields metadata.</param>
-        internal void SaveMetadata(int typeId, string typeName, string affKeyFieldName, IDictionary<string, int> fields)
+        internal void SaveMetadata(IBinaryTypeDescriptor desc, IDictionary<string, int> fields)
         {
+            Debug.Assert(desc != null);
+
             if (_metas == null)
             {
-                BinaryType meta =
-                    new BinaryType(typeId, typeName, fields, affKeyFieldName);
-
-                _metas = new Dictionary<int, IBinaryType>(1);
-
-                _metas[typeId] = meta;
+                _metas = new Dictionary<int, BinaryType>(1)
+                {
+                    {desc.TypeId, new BinaryType(desc, fields)}
+                };
             }
             else
             {
-                IBinaryType meta;
+                BinaryType meta;
 
-                if (_metas.TryGetValue(typeId, out meta))
+                if (_metas.TryGetValue(desc.TypeId, out meta))
                 {
-                    IDictionary<string, int> existingFields = ((BinaryType)meta).FieldsMap();
-
-                    foreach (KeyValuePair<string, int> field in fields)
+                    if (fields != null)
                     {
-                        if (!existingFields.ContainsKey(field.Key))
-                            existingFields[field.Key] = field.Value;
+                        IDictionary<string, int> existingFields = meta.GetFieldsMap();
+
+                        foreach (KeyValuePair<string, int> field in fields)
+                        {
+                            if (!existingFields.ContainsKey(field.Key))
+                                existingFields[field.Key] = field.Value;
+                        }
                     }
                 }
                 else
-                    _metas[typeId] = new BinaryType(typeId, typeName, fields, affKeyFieldName);
+                    _metas[desc.TypeId] = new BinaryType(desc, fields);
             }
         }
     }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
index 99af56d..e50279c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryTypeDescriptor.cs
@@ -30,74 +30,52 @@
         /// <summary>
         /// Type.
         /// </summary>
-        Type Type
-        {
-            get;
-        }
+        Type Type { get; }
 
         /// <summary>
         /// Type ID.
         /// </summary>
-        int TypeId
-        {
-            get;
-        }
+        int TypeId { get; }
 
         /// <summary>
         /// Type name.
         /// </summary>
-        string TypeName
-        {
-            get;
-        }
+        string TypeName { get; }
 
         /// <summary>
         /// User type flag.
         /// </summary>
-        bool UserType
-        {
-            get;
-        }
+        bool UserType { get; }
 
         /// <summary>
         /// Whether to cache deserialized value in IBinaryObject
         /// </summary>
-        bool KeepDeserialized
-        {
-            get;
-        }
+        bool KeepDeserialized { get; }
 
         /// <summary>
         /// Name converter.
         /// </summary>
-        IBinaryNameMapper NameMapper
-        {
-            get;
-        }
+        IBinaryNameMapper NameMapper { get; }
 
         /// <summary>
         /// Mapper.
         /// </summary>
-        IBinaryIdMapper IdMapper
-        {
-            get;
-        }
+        IBinaryIdMapper IdMapper { get; }
 
         /// <summary>
         /// Serializer.
         /// </summary>
-        IBinarySerializer Serializer
-        {
-            get;
-        }
+        IBinarySerializer Serializer { get; }
 
         /// <summary>
         /// Affinity key field name.
         /// </summary>
-        string AffinityKeyFieldName
-        {
-            get;
-        }
+        string AffinityKeyFieldName { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether this descriptor represents an enum type.
+        /// </summary>
+        bool IsEnum { get; }
 
         /// <summary>
         /// Write type structure.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
index 251610e..457830f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -19,7 +19,7 @@
 {
     using System;
     using System.Collections.Generic;
-    using System.Globalization;
+    using System.Diagnostics;
     using System.Linq;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
@@ -149,14 +149,14 @@
         /// </summary>
         /// <param name="writer">Writer.</param>
         /// <returns>Dictionary with metadata.</returns>
-        public void FinishMarshal(IBinaryWriter writer)
+        public void FinishMarshal(BinaryWriter writer)
         {
-            var meta = ((BinaryWriter) writer).GetBinaryTypes();
+            var metas = writer.GetBinaryTypes();
 
             var ignite = Ignite;
 
-            if (ignite != null && meta != null && meta.Count > 0)
-                ignite.PutBinaryTypes(meta);
+            if (ignite != null && metas != null && metas.Count > 0)
+                ignite.PutBinaryTypes(metas);
         }
 
         /// <summary>
@@ -266,7 +266,22 @@
                     return meta;
             }
 
-            return BinaryType.EmptyMeta;
+            return BinaryType.Empty;
+        }
+
+        /// <summary>
+        /// Puts the binary type metadata to Ignite.
+        /// </summary>
+        /// <param name="desc">Descriptor.</param>
+        /// <param name="fields">Fields.</param>
+        public void PutBinaryType(IBinaryTypeDescriptor desc, IDictionary<string, int> fields = null)
+        {
+            Debug.Assert(desc != null);
+
+            GetBinaryTypeHandler(desc);  // ensure that handler exists
+
+            if (Ignite != null)
+                Ignite.PutBinaryTypes(new[] {new BinaryType(desc, fields)});
         }
 
         /// <summary>
@@ -287,7 +302,7 @@
                         IDictionary<int, BinaryTypeHolder> metas0 =
                             new Dictionary<int, BinaryTypeHolder>(_metas);
 
-                        holder = new BinaryTypeHolder(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName);
+                        holder = new BinaryTypeHolder(desc.TypeId, desc.TypeName, desc.AffinityKeyFieldName, desc.IsEnum);
 
                         metas0[desc.TypeId] = holder;
 
@@ -298,7 +313,7 @@
 
             if (holder != null)
             {
-                ICollection<int> ids = holder.FieldIds();
+                ICollection<int> ids = holder.GetFieldIds();
 
                 bool newType = ids.Count == 0 && !holder.Saved();
 
@@ -312,23 +327,20 @@
         /// Callback invoked when metadata has been sent to the server and acknowledged by it.
         /// </summary>
         /// <param name="newMetas">Binary types.</param>
-        public void OnBinaryTypesSent(IDictionary<int, IBinaryType> newMetas)
+        public void OnBinaryTypesSent(IEnumerable<BinaryType> newMetas)
         {
-            foreach (KeyValuePair<int, IBinaryType> metaEntry in newMetas)
+            foreach (var meta in newMetas)
             {
-                BinaryType meta = (BinaryType) metaEntry.Value;
+                var mergeInfo = new Dictionary<int, Tuple<string, int>>(meta.GetFieldsMap().Count);
 
-                IDictionary<int, Tuple<string, int>> mergeInfo =
-                    new Dictionary<int, Tuple<string, int>>(meta.FieldsMap().Count);
-
-                foreach (KeyValuePair<string, int> fieldMeta in meta.FieldsMap())
+                foreach (KeyValuePair<string, int> fieldMeta in meta.GetFieldsMap())
                 {
-                    int fieldId = BinaryUtils.FieldId(metaEntry.Key, fieldMeta.Key, null, null);
+                    int fieldId = BinaryUtils.FieldId(meta.TypeId, fieldMeta.Key, null, null);
 
                     mergeInfo[fieldId] = new Tuple<string, int>(fieldMeta.Key, fieldMeta.Value);
                 }
 
-                _metas[metaEntry.Key].Merge(mergeInfo);
+                _metas[meta.TypeId].Merge(mergeInfo);
             }
         }
         
@@ -396,7 +408,7 @@
             if (type != null)
             {
                 // Type is found.
-                var typeName = GetTypeName(type);
+                var typeName = BinaryUtils.GetTypeName(type);
 
                 int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper);
 
@@ -408,8 +420,15 @@
                 if (refSerializer != null)
                     refSerializer.Register(type, typeId, nameMapper, idMapper);
 
+                if (typeCfg.IsEnum != type.IsEnum)
+                    throw new BinaryObjectException(
+                        string.Format(
+                            "Invalid IsEnum flag in binary type configuration. " +
+                            "Configuration value: IsEnum={0}, actual type: IsEnum={1}",
+                            typeCfg.IsEnum, type.IsEnum));
+
                 AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer,
-                    typeCfg.AffinityKeyFieldName);
+                    typeCfg.AffinityKeyFieldName, type.IsEnum);
             }
             else
             {
@@ -419,7 +438,7 @@
                 int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper);
 
                 AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null,
-                    typeCfg.AffinityKeyFieldName);
+                    typeCfg.AffinityKeyFieldName, typeCfg.IsEnum);
             }
         }
 
@@ -434,7 +453,7 @@
                 ? BinarizableSerializer.Instance 
                 : null;
         }
-        
+
         /// <summary>
         /// Add type.
         /// </summary>
@@ -447,9 +466,10 @@
         /// <param name="idMapper">ID mapper.</param>
         /// <param name="serializer">Serializer.</param>
         /// <param name="affKeyFieldName">Affinity key field name.</param>
+        /// <param name="isEnum">Enum flag.</param>
         private void AddType(Type type, int typeId, string typeName, bool userType, 
             bool keepDeserialized, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper,
-            IBinarySerializer serializer, string affKeyFieldName)
+            IBinarySerializer serializer, string affKeyFieldName, bool isEnum)
         {
             long typeKey = BinaryUtils.TypeKey(userType, typeId);
 
@@ -470,9 +490,8 @@
             if (userType && _typeNameToDesc.ContainsKey(typeName))
                 throw new BinaryObjectException("Conflicting type name: " + typeName);
 
-            IBinaryTypeDescriptor descriptor =
-                new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, serializer,
-                    keepDeserialized, affKeyFieldName);
+            var descriptor = new BinaryFullTypeDescriptor(type, typeId, typeName, userType, nameMapper, idMapper, 
+                serializer, keepDeserialized, affKeyFieldName, isEnum);
 
             if (type != null)
                 _typeToDesc[type] = descriptor;
@@ -492,7 +511,7 @@
 
             var serializer = new BinarySystemTypeSerializer<T>(ctor);
 
-            AddType(type, typeId, GetTypeName(type), false, false, null, null, serializer, null);
+            AddType(type, typeId, BinaryUtils.GetTypeName(type), false, false, null, null, serializer, null, false);
         }
 
         /// <summary>
@@ -516,22 +535,5 @@
             AddSystemType(BinaryUtils.TypeMessageListenerHolder, w => new MessageListenerHolder(w));
             AddSystemType(BinaryUtils.TypeStreamReceiverHolder, w => new StreamReceiverHolder(w));
         }
-
-        /// <summary>
-        /// Gets the name of the type.
-        /// </summary>
-        /// <param name="type">The type.</param>
-        /// <returns>
-        /// Simple type name for non-generic types; simple type name with appended generic arguments for generic types.
-        /// </returns>
-        private static string GetTypeName(Type type)
-        {
-            if (!type.IsGenericType)
-                return type.Name;
-
-            var args = type.GetGenericArguments().Select(GetTypeName).Aggregate((x, y) => x + "," + y);
-
-            return string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", type.Name, args);
-        }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs
index 3e9a28d..476e651 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryType.cs
@@ -27,9 +27,8 @@
     internal class BinaryType : IBinaryType
     {
         /** Empty metadata. */
-        [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
-        public static readonly BinaryType EmptyMeta =
-            new BinaryType(BinaryUtils.TypeObject, BinaryTypeNames.TypeNameObject, null, null);
+        public static readonly BinaryType Empty =
+            new BinaryType(BinaryUtils.TypeObject, BinaryTypeNames.TypeNameObject, null, null, false);
 
         /** Empty dictionary. */
         private static readonly IDictionary<string, int> EmptyDict = new Dictionary<string, int>();
@@ -37,82 +36,74 @@
         /** Empty list. */
         private static readonly ICollection<string> EmptyList = new List<string>().AsReadOnly();
 
+        /** Type name map. */
+        private static readonly string[] TypeNames = new string[byte.MaxValue];
+
         /** Fields. */
         private readonly IDictionary<string, int> _fields;
 
+        /** Enum flag. */
+        private readonly bool _isEnum;
+
+        /** Type id. */
+        private readonly int _typeId;
+
+        /** Type name. */
+        private readonly string _typeName;
+
+        /** Aff key field name. */
+        private readonly string _affinityKeyFieldName;
+
+        /// <summary>
+        /// Initializes the <see cref="BinaryType"/> class.
+        /// </summary>
+        static BinaryType()
+        {
+            TypeNames[BinaryUtils.TypeBool] = BinaryTypeNames.TypeNameBool;
+            TypeNames[BinaryUtils.TypeByte] = BinaryTypeNames.TypeNameByte;
+            TypeNames[BinaryUtils.TypeShort] = BinaryTypeNames.TypeNameShort;
+            TypeNames[BinaryUtils.TypeChar] = BinaryTypeNames.TypeNameChar;
+            TypeNames[BinaryUtils.TypeInt] = BinaryTypeNames.TypeNameInt;
+            TypeNames[BinaryUtils.TypeLong] = BinaryTypeNames.TypeNameLong;
+            TypeNames[BinaryUtils.TypeFloat] = BinaryTypeNames.TypeNameFloat;
+            TypeNames[BinaryUtils.TypeDouble] = BinaryTypeNames.TypeNameDouble;
+            TypeNames[BinaryUtils.TypeDecimal] = BinaryTypeNames.TypeNameDecimal;
+            TypeNames[BinaryUtils.TypeString] = BinaryTypeNames.TypeNameString;
+            TypeNames[BinaryUtils.TypeGuid] = BinaryTypeNames.TypeNameGuid;
+            TypeNames[BinaryUtils.TypeTimestamp] = BinaryTypeNames.TypeNameTimestamp;
+            TypeNames[BinaryUtils.TypeEnum] = BinaryTypeNames.TypeNameEnum;
+            TypeNames[BinaryUtils.TypeObject] = BinaryTypeNames.TypeNameObject;
+            TypeNames[BinaryUtils.TypeArrayBool] = BinaryTypeNames.TypeNameArrayBool;
+            TypeNames[BinaryUtils.TypeArrayByte] = BinaryTypeNames.TypeNameArrayByte;
+            TypeNames[BinaryUtils.TypeArrayShort] = BinaryTypeNames.TypeNameArrayShort;
+            TypeNames[BinaryUtils.TypeArrayChar] = BinaryTypeNames.TypeNameArrayChar;
+            TypeNames[BinaryUtils.TypeArrayInt] = BinaryTypeNames.TypeNameArrayInt;
+            TypeNames[BinaryUtils.TypeArrayLong] = BinaryTypeNames.TypeNameArrayLong;
+            TypeNames[BinaryUtils.TypeArrayFloat] = BinaryTypeNames.TypeNameArrayFloat;
+            TypeNames[BinaryUtils.TypeArrayDouble] = BinaryTypeNames.TypeNameArrayDouble;
+            TypeNames[BinaryUtils.TypeArrayDecimal] = BinaryTypeNames.TypeNameArrayDecimal;
+            TypeNames[BinaryUtils.TypeArrayString] = BinaryTypeNames.TypeNameArrayString;
+            TypeNames[BinaryUtils.TypeArrayGuid] = BinaryTypeNames.TypeNameArrayGuid;
+            TypeNames[BinaryUtils.TypeArrayTimestamp] = BinaryTypeNames.TypeNameArrayTimestamp;
+            TypeNames[BinaryUtils.TypeArrayEnum] = BinaryTypeNames.TypeNameArrayEnum;
+            TypeNames[BinaryUtils.TypeArray] = BinaryTypeNames.TypeNameArrayObject;
+            TypeNames[BinaryUtils.TypeCollection] = BinaryTypeNames.TypeNameCollection;
+            TypeNames[BinaryUtils.TypeDictionary] = BinaryTypeNames.TypeNameMap;
+        }
+
         /// <summary>
         /// Get type name by type ID.
         /// </summary>
         /// <param name="typeId">Type ID.</param>
         /// <returns>Type name.</returns>
-        private static string ConvertTypeName(int typeId)
+        private static string GetTypeName(int typeId)
         {
-            switch (typeId)
-            {
-                case BinaryUtils.TypeBool:
-                    return BinaryTypeNames.TypeNameBool;
-                case BinaryUtils.TypeByte:
-                    return BinaryTypeNames.TypeNameByte;
-                case BinaryUtils.TypeShort:
-                    return BinaryTypeNames.TypeNameShort;
-                case BinaryUtils.TypeChar:
-                    return BinaryTypeNames.TypeNameChar;
-                case BinaryUtils.TypeInt:
-                    return BinaryTypeNames.TypeNameInt;
-                case BinaryUtils.TypeLong:
-                    return BinaryTypeNames.TypeNameLong;
-                case BinaryUtils.TypeFloat:
-                    return BinaryTypeNames.TypeNameFloat;
-                case BinaryUtils.TypeDouble:
-                    return BinaryTypeNames.TypeNameDouble;
-                case BinaryUtils.TypeDecimal:
-                    return BinaryTypeNames.TypeNameDecimal;
-                case BinaryUtils.TypeString:
-                    return BinaryTypeNames.TypeNameString;
-                case BinaryUtils.TypeGuid:
-                    return BinaryTypeNames.TypeNameGuid;
-                case BinaryUtils.TypeTimestamp:
-                    return BinaryTypeNames.TypeNameTimestamp;
-                case BinaryUtils.TypeEnum:
-                    return BinaryTypeNames.TypeNameEnum;
-                case BinaryUtils.TypeBinary:
-                case BinaryUtils.TypeObject:
-                    return BinaryTypeNames.TypeNameObject;
-                case BinaryUtils.TypeArrayBool:
-                    return BinaryTypeNames.TypeNameArrayBool;
-                case BinaryUtils.TypeArrayByte:
-                    return BinaryTypeNames.TypeNameArrayByte;
-                case BinaryUtils.TypeArrayShort:
-                    return BinaryTypeNames.TypeNameArrayShort;
-                case BinaryUtils.TypeArrayChar:
-                    return BinaryTypeNames.TypeNameArrayChar;
-                case BinaryUtils.TypeArrayInt:
-                    return BinaryTypeNames.TypeNameArrayInt;
-                case BinaryUtils.TypeArrayLong:
-                    return BinaryTypeNames.TypeNameArrayLong;
-                case BinaryUtils.TypeArrayFloat:
-                    return BinaryTypeNames.TypeNameArrayFloat;
-                case BinaryUtils.TypeArrayDouble:
-                    return BinaryTypeNames.TypeNameArrayDouble;
-                case BinaryUtils.TypeArrayDecimal:
-                    return BinaryTypeNames.TypeNameArrayDecimal;
-                case BinaryUtils.TypeArrayString:
-                    return BinaryTypeNames.TypeNameArrayString;
-                case BinaryUtils.TypeArrayGuid:
-                    return BinaryTypeNames.TypeNameArrayGuid;
-                case BinaryUtils.TypeArrayTimestamp:
-                    return BinaryTypeNames.TypeNameArrayTimestamp;
-                case BinaryUtils.TypeArrayEnum:
-                    return BinaryTypeNames.TypeNameArrayEnum;
-                case BinaryUtils.TypeArray:
-                    return BinaryTypeNames.TypeNameArrayObject;
-                case BinaryUtils.TypeCollection:
-                    return BinaryTypeNames.TypeNameCollection;
-                case BinaryUtils.TypeDictionary:
-                    return BinaryTypeNames.TypeNameMap;
-                default:
-                    throw new BinaryObjectException("Invalid type ID: " + typeId);
-            }
+            var typeName = (typeId >= 0 && typeId < TypeNames.Length) ? TypeNames[typeId] : null;
+
+            if (typeName != null)
+                return typeName;
+
+            throw new BinaryObjectException("Invalid type ID: " + typeId);
         }
 
         /// <summary>
@@ -121,10 +112,22 @@
         /// <param name="reader">The reader.</param>
         public BinaryType(IBinaryRawReader reader)
         {
-            TypeId = reader.ReadInt();
-            TypeName = reader.ReadString();
-            AffinityKeyFieldName = reader.ReadString();
+            _typeId = reader.ReadInt();
+            _typeName = reader.ReadString();
+            _affinityKeyFieldName = reader.ReadString();
             _fields = reader.ReadDictionaryAsGeneric<string, int>();
+            _isEnum = reader.ReadBoolean();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BinaryType"/> class.
+        /// </summary>
+        /// <param name="desc">Descriptor.</param>
+        /// <param name="fields">Fields.</param>
+        public BinaryType(IBinaryTypeDescriptor desc, IDictionary<string, int> fields = null) 
+            : this (desc.TypeId, desc.TypeName, fields, desc.AffinityKeyFieldName, desc.IsEnum)
+        {
+            // No-op.
         }
 
         /// <summary>
@@ -134,25 +137,33 @@
         /// <param name="typeName">Type name.</param>
         /// <param name="fields">Fields.</param>
         /// <param name="affKeyFieldName">Affinity key field name.</param>
+        /// <param name="isEnum">Enum flag.</param>
         public BinaryType(int typeId, string typeName, IDictionary<string, int> fields,
-            string affKeyFieldName)
+            string affKeyFieldName, bool isEnum)
         {
-            TypeId = typeId;
-            TypeName = typeName;
-            AffinityKeyFieldName = affKeyFieldName;
+            _typeId = typeId;
+            _typeName = typeName;
+            _affinityKeyFieldName = affKeyFieldName;
             _fields = fields;
+            _isEnum = isEnum;
         }
 
         /// <summary>
         /// Type ID.
         /// </summary>
         /// <returns></returns>
-        public int TypeId { get; private set; }
+        public int TypeId
+        {
+            get { return _typeId; }
+        }
 
         /// <summary>
         /// Gets type name.
         /// </summary>
-        public string TypeName { get; private set; }
+        public string TypeName
+        {
+            get { return _typeName; }
+        }
 
         /// <summary>
         /// Gets field names for that type.
@@ -177,7 +188,7 @@
 
                 _fields.TryGetValue(fieldName, out typeId);
 
-                return ConvertTypeName(typeId);
+                return GetTypeName(typeId);
             }
             
             return null;
@@ -186,13 +197,22 @@
         /// <summary>
         /// Gets optional affinity key field name.
         /// </summary>
-        public string AffinityKeyFieldName { get; private set; }
+        public string AffinityKeyFieldName
+        {
+            get { return _affinityKeyFieldName; }
+        }
+
+        /** <inheritdoc /> */
+        public bool IsEnum
+        {
+            get { return _isEnum; }
+        }
 
         /// <summary>
         /// Gets fields map.
         /// </summary>
         /// <returns>Fields map.</returns>
-        public IDictionary<string, int> FieldsMap()
+        public IDictionary<string, int> GetFieldsMap()
         {
             return _fields ?? EmptyDict;
         }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs
index 524cda90..53ad77e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Metadata/BinaryTypeHolder.cs
@@ -19,7 +19,6 @@
 {
     using System;
     using System.Collections.Generic;
-    using Apache.Ignite.Core.Binary;
 
     /// <summary>
     /// Metadata for particular type.
@@ -35,11 +34,11 @@
         /** Affinity key field name. */
         private readonly string _affKeyFieldName;
 
-        /** Empty metadata when nothig is know about object fields yet. */
-        private readonly IBinaryType _emptyMeta;
+        /** Enum flag. */
+        private readonly bool _isEnum;
 
         /** Collection of know field IDs. */
-        private volatile ICollection<int> _ids;
+        private volatile HashSet<int> _ids;
 
         /** Last known unmodifiable metadata which is given to the user. */
         private volatile BinaryType _meta;
@@ -47,19 +46,19 @@
         /** Saved flag (set if type metadata was saved at least once). */
         private volatile bool _saved;
 
+
         /// <summary>
         /// Constructor.
         /// </summary>
         /// <param name="typeId">Type ID.</param>
         /// <param name="typeName">Type name.</param>
         /// <param name="affKeyFieldName">Affinity key field name.</param>
-        public BinaryTypeHolder(int typeId, string typeName, string affKeyFieldName)
+        public BinaryTypeHolder(int typeId, string typeName, string affKeyFieldName, bool isEnum)
         {
             _typeId = typeId;
             _typeName = typeName;
             _affKeyFieldName = affKeyFieldName;
-
-            _emptyMeta = new BinaryType(typeId, typeName, null, affKeyFieldName);
+            _isEnum = isEnum;
         }
 
         /// <summary>
@@ -72,21 +71,12 @@
         }
 
         /// <summary>
-        /// Get current type metadata.
-        /// </summary>
-        /// <value>Type metadata.</value>
-        public IBinaryType BinaryType
-        {
-            get { return _meta ?? _emptyMeta; }
-        }
-
-        /// <summary>
         /// Currently cached field IDs.
         /// </summary>
         /// <returns>Cached field IDs.</returns>
-        public ICollection<int> FieldIds()
+        public ICollection<int> GetFieldIds()
         {
-            ICollection<int> ids0 = _ids;
+            var ids0 = _ids;
 
             if (_ids == null)
             {
@@ -120,13 +110,13 @@
             lock (this)
             {
                 // 1. Create copies of the old meta.
-                ICollection<int> ids0 = _ids;
+                var ids0 = _ids;
                 BinaryType meta0 = _meta;
 
-                ICollection<int> newIds = ids0 != null ? new HashSet<int>(ids0) : new HashSet<int>();
+                var newIds = ids0 != null ? new HashSet<int>(ids0) : new HashSet<int>();
 
                 IDictionary<string, int> newFields = meta0 != null ?
-                    new Dictionary<string, int>(meta0.FieldsMap()) : new Dictionary<string, int>(newMap.Count);
+                    new Dictionary<string, int>(meta0.GetFieldsMap()) : new Dictionary<string, int>(newMap.Count);
 
                 // 2. Add new fields.
                 foreach (KeyValuePair<int, Tuple<string, int>> newEntry in newMap)
@@ -139,7 +129,7 @@
                 }
 
                 // 3. Assign new meta. Order is important here: meta must be assigned before field IDs.
-                _meta = new BinaryType(_typeId, _typeName, newFields, _affKeyFieldName);
+                _meta = new BinaryType(_typeId, _typeName, newFields, _affKeyFieldName, _isEnum);
                 _ids = newIds;
             }
         }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
index 37d980e..af1b050 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
@@ -111,7 +111,7 @@
                     var meta = metaHnd.OnObjectWriteFinished();
 
                     if (meta != null)
-                        writer.SaveMetadata(_desc.TypeId, _desc.TypeName, _desc.AffinityKeyFieldName, meta);
+                        writer.SaveMetadata(_desc, meta);
                 }
             }
         }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
index ded671a..2fcada3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs
@@ -31,6 +31,7 @@
     using Apache.Ignite.Core.DataStructures;
     using Apache.Ignite.Core.Events;
     using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.Metadata;
     using Apache.Ignite.Core.Impl.Cache;
     using Apache.Ignite.Core.Impl.Cluster;
     using Apache.Ignite.Core.Impl.Common;
@@ -66,7 +67,7 @@
         private readonly ClusterGroupImpl _prj;
 
         /** Binary. */
-        private readonly IgniteBinary _igniteBinary;
+        private readonly Binary.Binary _binary;
 
         /** Cached proxy. */
         private readonly IgniteProxy _proxy;
@@ -117,7 +118,7 @@
 
             _prj = new ClusterGroupImpl(proc, UU.ProcessorProjection(proc), marsh, this, null);
 
-            _igniteBinary = new IgniteBinary(marsh);
+            _binary = new Binary.Binary(marsh);
 
             _proxy = new IgniteProxy(this);
 
@@ -394,9 +395,9 @@
         }
 
         /** <inheritdoc /> */
-        public IIgniteBinary GetBinary()
+        public IBinary GetBinary()
         {
-            return _igniteBinary;
+            return _binary;
         }
 
         /** <inheritdoc /> */
@@ -472,7 +473,7 @@
         /// Put metadata to Grid.
         /// </summary>
         /// <param name="metas">Metadata.</param>
-        internal void PutBinaryTypes(IDictionary<int, IBinaryType> metas)
+        internal void PutBinaryTypes(ICollection<BinaryType> metas)
         {
             _prj.PutBinaryTypes(metas);
         }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
index 113f700..36aac1a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs
@@ -275,7 +275,7 @@
         }
 
         /** <inheritdoc /> */
-        public IIgniteBinary GetBinary()
+        public IBinary GetBinary()
         {
             return _ignite.GetBinary();
         }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs
index 115f30d..4a4f93b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/PlatformTarget.cs
@@ -23,7 +23,6 @@
     using System.Diagnostics.CodeAnalysis;
     using System.IO;
     using System.Threading.Tasks;
-    using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Binary.Metadata;
@@ -581,7 +580,7 @@
         /// Put binary types to Grid.
         /// </summary>
         /// <param name="types">Binary types.</param>
-        internal void PutBinaryTypes(IDictionary<int, IBinaryType> types)
+        internal void PutBinaryTypes(ICollection<BinaryType> types)
         {
             DoOutOp(OpMeta, stream =>
             {
@@ -589,15 +588,15 @@
 
                 metaWriter.WriteInt(types.Count);
 
-                foreach (var meta in types.Values)
+                foreach (var meta in types)
                 {
-                    BinaryType meta0 = (BinaryType)meta;
+                    BinaryType meta0 = meta;
 
                     metaWriter.WriteInt(meta0.TypeId);
                     metaWriter.WriteString(meta0.TypeName);
                     metaWriter.WriteString(meta0.AffinityKeyFieldName);
 
-                    IDictionary<string, int> fields = meta0.FieldsMap();
+                    IDictionary<string, int> fields = meta0.GetFieldsMap();
 
                     metaWriter.WriteInt(fields.Count);
 
@@ -606,6 +605,8 @@
                         metaWriter.WriteString(field.Key);
                         metaWriter.WriteInt(field.Value);
                     }
+
+                    metaWriter.WriteBoolean(meta.IsEnum);
                 }
 
                 _marsh.FinishMarshal(metaWriter);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs
index a27bffe..0bc7172 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs
@@ -67,8 +67,8 @@
             {
                 var reader = marsh.StartUnmarshal(stream).GetRawReader();
 
-                concurrency = reader.ReadEnum<TransactionConcurrency>();
-                isolation = reader.ReadEnum<TransactionIsolation>();
+                concurrency = (TransactionConcurrency) reader.ReadInt();
+                isolation = (TransactionIsolation) reader.ReadInt();
                 timeout = TimeSpan.FromMilliseconds(reader.ReadLong());
             });
 
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Messaging/MessagingExample.cs b/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Messaging/MessagingExample.cs
index ad28afe..3c74a42 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Messaging/MessagingExample.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Messaging/MessagingExample.cs
@@ -72,13 +72,14 @@
                     var unorderedCounter = new CountdownEvent(msgCount);
 
                     localMessaging.LocalListen(new LocalListener(unorderedCounter), Topic.Unordered);
+
                     localMessaging.LocalListen(new LocalListener(orderedCounter), Topic.Ordered);
 
                     // Set up remote listeners
                     var remoteMessaging = remotes.GetMessaging();
 
-                    remoteMessaging.RemoteListen(new RemoteUnorderedListener(), Topic.Unordered);
-                    remoteMessaging.RemoteListen(new RemoteOrderedListener(), Topic.Ordered);
+                    var idUnordered = remoteMessaging.RemoteListen(new RemoteUnorderedListener(), Topic.Unordered);
+                    var idOrdered = remoteMessaging.RemoteListen(new RemoteOrderedListener(), Topic.Ordered);
 
                     // Send unordered
                     Console.WriteLine(">>> Sending unordered messages...");
@@ -101,6 +102,10 @@
 
                     unorderedCounter.Wait();
                     orderedCounter.Wait();
+
+                    // Unsubscribe
+                    remoteMessaging.StopRemoteListen(idUnordered);
+                    remoteMessaging.StopRemoteListen(idOrdered);
                 }
             }
 
diff --git a/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Services/ServicesExample.cs b/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Services/ServicesExample.cs
index 121a5c4..77eb253 100644
--- a/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Services/ServicesExample.cs
+++ b/modules/platforms/dotnet/examples/Apache.Ignite.Examples/Services/ServicesExample.cs
@@ -72,6 +72,10 @@
 
                 ignite.GetServices().CancelAll();
             }
+
+            Console.WriteLine();
+            Console.WriteLine(">>> Example finished, press any key to exit ...");
+            Console.ReadKey();
         }
     }
 }
diff --git a/modules/platforms/dotnet/examples/Config/example-cache-query.xml b/modules/platforms/dotnet/examples/Config/example-cache-query.xml
index a3b854b..5bc9399 100644
--- a/modules/platforms/dotnet/examples/Config/example-cache-query.xml
+++ b/modules/platforms/dotnet/examples/Config/example-cache-query.xml
@@ -38,7 +38,14 @@
                                 <value>Apache.Ignite.ExamplesDll.Binary.Employee</value>
                                 <value>Apache.Ignite.ExamplesDll.Binary.EmployeeKey</value>
                                 <value>Apache.Ignite.ExamplesDll.Binary.Organization</value>
-                                <value>Apache.Ignite.ExamplesDll.Binary.OrganizationType</value>
+                            </list>
+                        </property>
+                        <property name="typesConfiguration">
+                            <list>
+                                <bean class="org.apache.ignite.platform.dotnet.PlatformDotNetBinaryTypeConfiguration">
+                                    <property name="typeName" value="Apache.Ignite.ExamplesDll.Binary.OrganizationType" />
+                                    <property name="enum" value="true" />
+                                </bean>
                             </list>
                         </property>
                     </bean>
diff --git a/modules/platforms/dotnet/examples/Config/example-cache.xml b/modules/platforms/dotnet/examples/Config/example-cache.xml
index 21a6a76..949f3a4 100644
--- a/modules/platforms/dotnet/examples/Config/example-cache.xml
+++ b/modules/platforms/dotnet/examples/Config/example-cache.xml
@@ -37,7 +37,14 @@
                                 <value>Apache.Ignite.ExamplesDll.Binary.Employee</value>
                                 <value>Apache.Ignite.ExamplesDll.Binary.EmployeeKey</value>
                                 <value>Apache.Ignite.ExamplesDll.Binary.Organization</value>
-                                <value>Apache.Ignite.ExamplesDll.Binary.OrganizationType</value>
+                            </list>
+                        </property>
+                        <property name="typesConfiguration">
+                            <list>
+                                <bean class="org.apache.ignite.platform.dotnet.PlatformDotNetBinaryTypeConfiguration">
+                                    <property name="typeName" value="Apache.Ignite.ExamplesDll.Binary.OrganizationType" />
+                                    <property name="enum" value="true" />
+                                </bean>
                             </list>
                         </property>
                     </bean>
diff --git a/modules/scalar/pom.xml b/modules/scalar/pom.xml
index 4948f9d..386d2b8 100644
--- a/modules/scalar/pom.xml
+++ b/modules/scalar/pom.xml
@@ -72,7 +72,7 @@
         <dependency>
             <groupId>org.scalatest</groupId>
             <artifactId>scalatest_2.11</artifactId>
-            <version>2.2.2</version>
+            <version>2.2.4</version>
             <scope>test</scope>
             <exclusions>
                 <exclusion>
diff --git a/modules/scalar/src/test/resources/spring-ping-pong-partner.xml b/modules/scalar/src/test/resources/spring-ping-pong-partner.xml
index adc39ec..0f35c44 100644
--- a/modules/scalar/src/test/resources/spring-ping-pong-partner.xml
+++ b/modules/scalar/src/test/resources/spring-ping-pong-partner.xml
@@ -42,24 +42,6 @@
         <property name="peerClassLoadingEnabled" value="true"/>
 
         <!--
-            Configure optimized marshaller.
-        -->
-        <property name="marshaller">
-            <bean class="org.apache.ignite.marshaller.optimized.OptimizedMarshaller">
-                <!--
-                    For better performance set this property to true in case
-                    all marshalled classes implement java.io.Serializable.
-                    Default value is true.
-
-                    Note, that it is recommended to implement java.io.Externalizable
-                    instead of java.io.Serializable for smaller network footprint
-                    and even better performance.
-                -->
-                <property name="requireSerializable" value="false"/>
-            </bean>
-        </property>
-
-        <!--
             Enable cache events.
         -->
         <property name="includeEventTypes">
diff --git a/modules/spark/pom.xml b/modules/spark/pom.xml
index 942652c5..93c3e41 100644
--- a/modules/spark/pom.xml
+++ b/modules/spark/pom.xml
@@ -52,7 +52,7 @@
         <dependency>
             <groupId>org.scala-lang</groupId>
             <artifactId>scala-library</artifactId>
-            <version>2.11.2</version>
+            <version>2.11.7</version>
         </dependency>
 
         <dependency>
@@ -89,7 +89,7 @@
         <dependency>
             <groupId>org.scalatest</groupId>
             <artifactId>scalatest_2.11</artifactId>
-            <version>2.2.2</version>
+            <version>2.2.4</version>
             <scope>test</scope>
             <exclusions>
                 <exclusion>
diff --git a/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/package-info.java b/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/package-info.java
new file mode 100644
index 0000000..2ccce9e
--- /dev/null
+++ b/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains cache store session listener based on Spring transaction management.
+ */
+package org.apache.ignite.cache.store.spring;
\ No newline at end of file
diff --git a/modules/twitter/src/main/java/org/apache/ignite/stream/twitter/package-info.java b/modules/twitter/src/main/java/org/apache/ignite/stream/twitter/package-info.java
new file mode 100644
index 0000000..cff6d81
--- /dev/null
+++ b/modules/twitter/src/main/java/org/apache/ignite/stream/twitter/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Twitter Streamer.
+ */
+package org.apache.ignite.stream.twitter;
\ No newline at end of file
diff --git a/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/IgniteTwitterStreamerTestSuite.java b/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/IgniteTwitterStreamerTestSuite.java
index b458bed..e07aaec 100644
--- a/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/IgniteTwitterStreamerTestSuite.java
+++ b/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/IgniteTwitterStreamerTestSuite.java
@@ -17,16 +17,21 @@
 
 package org.apache.ignite.stream.twitter;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import junit.framework.TestSuite;
 
 /**
  * Twitter streamer tests.
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    IgniteTwitterStreamerTest.class
-})
-public class IgniteTwitterStreamerTestSuite {
+public class IgniteTwitterStreamerTestSuite extends TestSuite {
+    /**
+     * @return Twitter streamer tests suite.
+     * @throws Exception If failed.
+     */
+    public static TestSuite suite() throws Exception {
+        TestSuite suite = new TestSuite("Twitter streamed Test Suite");
 
+        suite.addTestSuite(IgniteTwitterStreamerTest.class);
+
+        return suite;
+    }
 }
diff --git a/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/package-info.java b/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/package-info.java
new file mode 100644
index 0000000..cff6d81
--- /dev/null
+++ b/modules/twitter/src/test/java/org/apache/ignite/stream/twitter/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains implementation of Twitter Streamer.
+ */
+package org.apache.ignite.stream.twitter;
\ No newline at end of file
diff --git a/modules/yardstick/config/ignite-int-max-values-offheap-config.xml b/modules/yardstick/config/ignite-int-max-values-offheap-config.xml
new file mode 100644
index 0000000..1aaab671
--- /dev/null
+++ b/modules/yardstick/config/ignite-int-max-values-offheap-config.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    Ignite Spring configuration file.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="peerClassLoadingEnabled" value="true"/>
+
+        <property name="marshaller">
+            <bean class="org.apache.ignite.marshaller.optimized.OptimizedMarshaller">
+                <property name="requireSerializable" value="false"/>
+            </bean>
+        </property>
+
+<!--
+        <property name="marshaller">
+            <bean class="org.apache.ignite.internal.portable.api.PortableMarshaller"/>
+        </property>
+-->
+
+        <property name="networkTimeout" value="600000"/>
+
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="networkTimeout" value="600000"/>
+
+                <property name="socketTimeout" value="600000"/>
+
+                <property name="ackTimeout" value="60000"/>
+
+                <property name="ipFinder">
+                    <!-- <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"> -->
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
+                        <!--
+                                                <property name="addresses">
+                                                    <list>
+                                                        &lt;!&ndash; In distributed environment, replace with actual host IP address. &ndash;&gt;
+                                                        <value>127.0.0.1:47500..47509</value>
+                                                    </list>
+                                                </property>
+                        -->
+                    </bean>
+                </property>
+            </bean>
+        </property>
+
+        <property name="cacheConfiguration">
+            <list>
+                <bean class="org.apache.ignite.configuration.CacheConfiguration">
+                    <property name="name" value="int-max-value-cache"/>
+                    <property name="cacheMode" value="PARTITIONED"/>
+                    <property name="backups" value="0"/>
+                    <property name="atomicityMode" value="ATOMIC"/>
+                    <property name="memoryMode" value="ONHEAP_TIERED"/>
+                    <property name="offHeapMaxMemory" value="#{32 * 1024 * 1024 * 1024L}"/>
+                    <property name="swapEnabled" value="false"/>
+                    <property name="evictionPolicy">
+                        <bean class="org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy">
+                            <property name="maxSize" value="4000000"/>
+                            <property name="batchSize" value="500000"/>
+                        </bean>
+                    </property>
+                </bean>
+            </list>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/yardstick/config/ignite-int-max-values-onheap-config.xml b/modules/yardstick/config/ignite-int-max-values-onheap-config.xml
new file mode 100644
index 0000000..d1359b3
--- /dev/null
+++ b/modules/yardstick/config/ignite-int-max-values-onheap-config.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    Ignite Spring configuration file.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="peerClassLoadingEnabled" value="true"/>
+
+        <property name="marshaller">
+            <bean class="org.apache.ignite.marshaller.optimized.OptimizedMarshaller">
+                <property name="requireSerializable" value="false"/>
+            </bean>
+        </property>
+
+<!--
+        <property name="marshaller">
+            <bean class="org.apache.ignite.internal.portable.api.PortableMarshaller"/>
+        </property>
+-->
+
+        <property name="networkTimeout" value="600000"/>
+
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="networkTimeout" value="600000"/>
+
+                <property name="socketTimeout" value="600000"/>
+
+                <property name="ackTimeout" value="60000"/>
+
+
+                <property name="ipFinder">
+                    <!-- <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"> -->
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
+                        <!--
+                                                <property name="addresses">
+                                                    <list>
+                                                        &lt;!&ndash; In distributed environment, replace with actual host IP address. &ndash;&gt;
+                                                        <value>127.0.0.1:47500..47509</value>
+                                                    </list>
+                                                </property>
+                        -->
+                    </bean>
+                </property>
+            </bean>
+        </property>
+
+        <property name="cacheConfiguration">
+            <list>
+                <bean class="org.apache.ignite.configuration.CacheConfiguration">
+                    <property name="name" value="int-max-value-cache"/>
+                    <property name="cacheMode" value="PARTITIONED"/>
+                    <property name="backups" value="0"/>
+                    <property name="atomicityMode" value="ATOMIC"/>
+                    <property name="memoryMode" value="ONHEAP_TIERED"/>
+                    <property name="offHeapMaxMemory" value="-1"/>
+                    <property name="swapEnabled" value="false"/>
+                </bean>
+            </list>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/yardstick/config/ignite-int-max-values-swap-config.xml b/modules/yardstick/config/ignite-int-max-values-swap-config.xml
new file mode 100644
index 0000000..8634b4f
--- /dev/null
+++ b/modules/yardstick/config/ignite-int-max-values-swap-config.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    Ignite Spring configuration file.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="peerClassLoadingEnabled" value="true"/>
+
+        <property name="marshaller">
+            <bean class="org.apache.ignite.marshaller.optimized.OptimizedMarshaller">
+                <property name="requireSerializable" value="false"/>
+            </bean>
+        </property>
+
+<!--
+        <property name="marshaller">
+            <bean class="org.apache.ignite.internal.portable.api.PortableMarshaller"/>
+        </property>
+-->
+
+        <property name="networkTimeout" value="600000"/>
+
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="networkTimeout" value="600000"/>
+
+                <property name="socketTimeout" value="600000"/>
+
+                <property name="ackTimeout" value="60000"/>
+
+                <property name="ipFinder">
+                    <!-- <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder"> -->
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
+                        <!--
+                                                <property name="addresses">
+                                                    <list>
+                                                        &lt;!&ndash; In distributed environment, replace with actual host IP address. &ndash;&gt;
+                                                        <value>127.0.0.1:47500..47509</value>
+                                                    </list>
+                                                </property>
+                        -->
+                    </bean>
+                </property>
+            </bean>
+        </property>
+
+        <property name="cacheConfiguration">
+            <list>
+                <bean class="org.apache.ignite.configuration.CacheConfiguration">
+                    <property name="name" value="int-max-value-cache"/>
+                    <property name="cacheMode" value="PARTITIONED"/>
+                    <property name="backups" value="0"/>
+                    <property name="atomicityMode" value="ATOMIC"/>
+                    <property name="memoryMode" value="ONHEAP_TIERED"/>
+                    <property name="offHeapMaxMemory" value="#{32 * 1024 * 1024 * 1024L}"/>
+                    <property name="swapEnabled" value="true"/>
+                    <property name="evictionPolicy">
+                        <bean class="org.apache.ignite.cache.eviction.fifo.FifoEvictionPolicy">
+                            <property name="maxSize" value="4000000"/>
+                            <property name="batchSize" value="500000"/>
+                        </bean>
+                    </property>
+                </bean>
+            </list>
+        </property>
+
+        <property name="swapSpaceSpi">
+            <bean class="org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi"/>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/yardstick/config/test-max-int-values-offheap.properties b/modules/yardstick/config/test-max-int-values-offheap.properties
new file mode 100644
index 0000000..5b4da20
--- /dev/null
+++ b/modules/yardstick/config/test-max-int-values-offheap.properties
@@ -0,0 +1,70 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Contains benchmarks for SQL queries.
+#
+
+# JVM options.
+# JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false"
+
+# Uncomment to enable concurrent garbage collection (GC) if you encounter long GC pauses.
+JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false \
+  -Xloggc:./gc${now0}.log \
+  -XX:+PrintGCDetails \
+  -XX:-PrintGCTimeStamps \
+  -verbose:gc \
+  -Xmx8g \
+  -Xms8g \
+  -XX:+UseParNewGC \
+  -XX:+UseConcMarkSweepGC \
+  -XX:+UseTLAB \
+  -XX:NewSize=1g \
+  -XX:MaxNewSize=1g \
+  -XX:MaxTenuringThreshold=0 \
+  -XX:SurvivorRatio=1024 \
+  -XX:+UseCMSInitiatingOccupancyOnly \
+  -XX:CMSInitiatingOccupancyFraction=60 \
+"
+
+# List of default probes.
+# Add DStatProbe or VmStatProbe if your OS supports it (e.g. if running on Linux).
+# BENCHMARK_DEFAULT_PROBES=ThroughputLatencyProbe,PercentileProbe
+
+# Packages where the specified benchmark is searched by reflection mechanism.
+BENCHMARK_PACKAGES=org.yardstickframework,org.apache.ignite.yardstick
+
+# Probe point writer class name.
+# BENCHMARK_WRITER=
+
+# Comma-separated list of the hosts to run BenchmarkServers on. 2 nodes on local host are enabled by default.
+SERVER_HOSTS=fosters-215,fosters-216,fosters-217,fosters-226,fosters-219,fosters-221,fosters-222,fosters-223
+
+# Comma-separated list of the hosts to run BenchmarkDrivers on. 1 node on local host is enabled by default.
+DRIVER_HOSTS=fosters-218
+
+# Remote username.
+# REMOTE_USER=
+
+# Number of nodes, used to wait for the specified number of nodes to start.
+nodesNum=$((`echo ${SERVER_HOSTS} | tr ',' '\n' | wc -l` + `echo ${DRIVER_HOSTS} | tr ',' '\n' | wc -l`))
+
+# Run configuration.
+# Note that each benchmark is set to run for 300 seconds (5 mins) with warm-up set to 60 seconds (1 minute).
+CONFIGS="\
+-cfg ${SCRIPT_DIR}/../config/ignite-int-max-values-offheap-config.xml -nn ${nodesNum} -b 0 -w 0 -d 9999999 -t 1 -sm PRIMARY_SYNC -dn IntMaxValueEntriesTest -sn IgniteNode -ds int-max-values-offheap\
+"
+
+
diff --git a/modules/yardstick/config/test-max-int-values-onheap.properties b/modules/yardstick/config/test-max-int-values-onheap.properties
new file mode 100644
index 0000000..d29800a
--- /dev/null
+++ b/modules/yardstick/config/test-max-int-values-onheap.properties
@@ -0,0 +1,70 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Contains benchmarks for SQL queries.
+#
+
+# JVM options.
+# JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false"
+
+# Uncomment to enable concurrent garbage collection (GC) if you encounter long GC pauses.
+JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false \
+  -Xloggc:./gc${now0}.log \
+  -XX:+PrintGCDetails \
+  -XX:-PrintGCTimeStamps \
+  -verbose:gc \
+  -Xmx92g \
+  -Xms32g \
+  -XX:+UseParNewGC \
+  -XX:+UseConcMarkSweepGC \
+  -XX:+UseTLAB \
+  -XX:NewSize=4g \
+  -XX:MaxNewSize=4g \
+  -XX:MaxTenuringThreshold=0 \
+  -XX:SurvivorRatio=1024 \
+  -XX:+UseCMSInitiatingOccupancyOnly \
+  -XX:CMSInitiatingOccupancyFraction=60 \
+"
+
+# List of default probes.
+# Add DStatProbe or VmStatProbe if your OS supports it (e.g. if running on Linux).
+# BENCHMARK_DEFAULT_PROBES=ThroughputLatencyProbe,PercentileProbe
+
+# Packages where the specified benchmark is searched by reflection mechanism.
+BENCHMARK_PACKAGES=org.yardstickframework,org.apache.ignite.yardstick
+
+# Probe point writer class name.
+# BENCHMARK_WRITER=
+
+# Comma-separated list of the hosts to run BenchmarkServers on. 2 nodes on local host are enabled by default.
+SERVER_HOSTS=fosters-215,fosters-216,fosters-217,fosters-226,fosters-219,fosters-221,fosters-222,fosters-223
+
+# Comma-separated list of the hosts to run BenchmarkDrivers on. 1 node on local host is enabled by default.
+DRIVER_HOSTS=fosters-218
+
+# Remote username.
+# REMOTE_USER=
+
+# Number of nodes, used to wait for the specified number of nodes to start.
+nodesNum=$((`echo ${SERVER_HOSTS} | tr ',' '\n' | wc -l` + `echo ${DRIVER_HOSTS} | tr ',' '\n' | wc -l`))
+
+# Run configuration.
+# Note that each benchmark is set to run for 300 seconds (5 mins) with warm-up set to 60 seconds (1 minute).
+CONFIGS="\
+-cfg ${SCRIPT_DIR}/../config/ignite-int-max-values-onheap-config.xml -nn ${nodesNum} -b 0 -w 0 -d 9999999 -t 1 -sm PRIMARY_SYNC -dn IntMaxValueEntriesTest -sn IgniteNode -ds int-max-values-onheap\
+"
+
+
diff --git a/modules/yardstick/config/test-max-int-values-swap.properties b/modules/yardstick/config/test-max-int-values-swap.properties
new file mode 100644
index 0000000..203f004
--- /dev/null
+++ b/modules/yardstick/config/test-max-int-values-swap.properties
@@ -0,0 +1,69 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Contains benchmarks for SQL queries.
+#
+
+# JVM options.
+# JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false"
+
+# Uncomment to enable concurrent garbage collection (GC) if you encounter long GC pauses.
+JVM_OPTS=${JVM_OPTS}" -DIGNITE_QUIET=false \
+  -Xloggc:./gc${now0}.log \
+  -XX:+PrintGCDetails \
+  -XX:-PrintGCTimeStamps \
+  -verbose:gc \
+  -Xmx8g \
+  -Xms8g \
+  -XX:+UseParNewGC \
+  -XX:+UseConcMarkSweepGC \
+  -XX:+UseTLAB \
+  -XX:NewSize=1g \
+  -XX:MaxNewSize=1g \
+  -XX:MaxTenuringThreshold=0 \
+  -XX:SurvivorRatio=1024 \
+  -XX:+UseCMSInitiatingOccupancyOnly \
+  -XX:CMSInitiatingOccupancyFraction=60 \
+"
+
+# List of default probes.
+# Add DStatProbe or VmStatProbe if your OS supports it (e.g. if running on Linux).
+# BENCHMARK_DEFAULT_PROBES=ThroughputLatencyProbe,PercentileProbe
+
+# Packages where the specified benchmark is searched by reflection mechanism.
+BENCHMARK_PACKAGES=org.yardstickframework,org.apache.ignite.yardstick
+
+# Probe point writer class name.
+# BENCHMARK_WRITER=
+
+# Comma-separated list of the hosts to run BenchmarkServers on. 2 nodes on local host are enabled by default.
+SERVER_HOSTS=fosters-215,fosters-216,fosters-217,fosters-226,fosters-219,fosters-221,fosters-222,fosters-223
+
+# Comma-separated list of the hosts to run BenchmarkDrivers on. 1 node on local host is enabled by default.
+DRIVER_HOSTS=fosters-218
+
+# Remote username.
+# REMOTE_USER=
+
+# Number of nodes, used to wait for the specified number of nodes to start.
+nodesNum=$((`echo ${SERVER_HOSTS} | tr ',' '\n' | wc -l` + `echo ${DRIVER_HOSTS} | tr ',' '\n' | wc -l`))
+
+# Run configuration.
+# Note that each benchmark is set to run for 300 seconds (5 mins) with warm-up set to 60 seconds (1 minute).
+CONFIGS="\
+-cfg ${SCRIPT_DIR}/../config/ignite-int-max-values-swap-config.xml -nn ${nodesNum} -b 0 -w 0 -d 9999999 -t 1 -sm PRIMARY_SYNC -dn IntMaxValueEntriesTest -sn IgniteNode -ds int-max-values-swap\
+"
+
diff --git a/modules/yardstick/src/main/java/org/apache/ignite/yardstick/cache/IntMaxValueEntriesTest.java b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/cache/IntMaxValueEntriesTest.java
new file mode 100644
index 0000000..06ca3b7
--- /dev/null
+++ b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/cache/IntMaxValueEntriesTest.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.yardstick.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+import javax.cache.Cache;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteDataStreamer;
+import org.jsr166.LongAdder8;
+
+import static org.yardstickframework.BenchmarkUtils.println;
+
+/**
+ *
+ */
+public class IntMaxValueEntriesTest extends IgniteCacheAbstractBenchmark {
+    /** Threads. */
+    private static final int THREADS = 16;
+
+    /** Keys lo. */
+    private static final int KEYS_LO = -100_000;
+
+    /** Keys hi. */
+    private static final long KEYS_HI = Integer.MAX_VALUE;
+
+    /** Report delta. */
+    private static final int REPORT_DELTA = 1_000_000;
+
+    /** Cache name. */
+    private static final String CACHE_NAME = "int-max-value-cache";
+
+    /** {@inheritDoc} */
+    @Override public boolean test(Map<Object, Object> ctx) throws Exception {
+        final IgniteCache<Integer, Object> cache = cache();
+
+        final IgniteDataStreamer<Integer, Object> stmr = ignite().dataStreamer(cache.getName());
+
+        final List<Thread> threads = new ArrayList<>(THREADS);
+
+        final LongAdder8 addedCnt = new LongAdder8();
+
+        int delta = (int)((KEYS_HI + Math.abs(KEYS_LO)) / THREADS);
+
+        System.out.println("Delta: " + delta);
+
+        for (int i = 0; i < THREADS; i++) {
+            final int lo = i == 0 ? KEYS_LO : delta * i + 1;
+
+            final int hi = i == THREADS - 1 ? (int)KEYS_HI : (int)((long)delta * (i + 1));
+
+            Thread t = new Thread(new Runnable() {
+                @Override public void run() {
+                    ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+                    byte val = (byte)rnd.nextInt();
+
+                    println("Start from " + lo + " to " + hi);
+
+                    for (int j = lo, k = 0; j < hi; j++, k++) {
+                        stmr.addData(j, val++);
+
+                        addedCnt.increment();
+
+                        if (k % REPORT_DELTA == 0)
+                            println(addedCnt.sum() + " entries");
+                    }
+
+                    println("Thread finished. " + addedCnt.sum() + " entries.");
+                }
+            });
+
+            threads.add(t);
+            t.start();
+        }
+
+        for (Thread thread : threads)
+            thread.join();
+
+        println("All threads finished. " + addedCnt.sum() + " entries.");
+
+        println("Streamer flush");
+
+        stmr.flush();
+
+        println("Streamer flushed");
+
+        println("Calculating cache size");
+        println("Cache size: " + cache.size());
+
+        println("Calculating long cache size");
+        println("Cache size long: " + cache.sizeLong());
+
+        Thread.sleep(10000);
+
+        println("Iterating started");
+
+        long cnt = 0;
+
+        for (Cache.Entry<Integer, Object> ignored : cache) {
+            cnt++;
+
+            if (cnt > 0 && cnt % REPORT_DELTA == 0)
+                println("Iterated via " + cnt + " entries");
+        }
+
+        println("Iterated via " + cnt + " entries");
+
+        cache.destroy();
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteCache cache() {
+        return ignite().cache(CACHE_NAME);
+    }
+}
diff --git a/modules/yarn/pom.xml b/modules/yarn/pom.xml
index 2b758dc..d1f6390 100644
--- a/modules/yarn/pom.xml
+++ b/modules/yarn/pom.xml
@@ -35,20 +35,20 @@
     <url>http://ignite.apache.org</url>
 
     <properties>
-        <hadoop.version>2.7.0</hadoop.version>
+        <hadoop-yarn.version>2.7.0</hadoop-yarn.version>
     </properties>
 
     <dependencies>
         <dependency>
             <groupId>org.apache.hadoop</groupId>
             <artifactId>hadoop-yarn-client</artifactId>
-            <version>${hadoop.version}</version>
+            <version>${hadoop-yarn.version}</version>
         </dependency>
 
         <dependency>
             <groupId>org.apache.hadoop</groupId>
             <artifactId>hadoop-common</artifactId>
-            <version>${hadoop.version}</version>
+            <version>${hadoop-yarn.version}</version>
         </dependency>
 
         <dependency>
diff --git a/modules/yarn/src/test/java/org/apache/ignite/yarn/IgniteApplicationMasterSelfTest.java b/modules/yarn/src/test/java/org/apache/ignite/yarn/IgniteApplicationMasterSelfTest.java
index 2173701..97f6a12 100644
--- a/modules/yarn/src/test/java/org/apache/ignite/yarn/IgniteApplicationMasterSelfTest.java
+++ b/modules/yarn/src/test/java/org/apache/ignite/yarn/IgniteApplicationMasterSelfTest.java
@@ -382,8 +382,15 @@
             return 0;
         }
 
-        /** {@inheritDoc} */
-        @Override public void updateBlacklist(List blacklistAdditions, List blacklistRemovals) {
+        /**
+         * Update application's blacklist with addition or removal resources.
+         *
+         * @param blacklistAdditions list of resources which should be added to the
+         *        application blacklist
+         * @param blacklistRemovals list of resources which should be removed from the
+         *        application blacklist
+         */
+        public void updateBlacklist(List blacklistAdditions, List blacklistRemovals) {
             // No-op.
         }
     }
diff --git a/modules/zookeeper/README.txt b/modules/zookeeper/README.txt
new file mode 100644
index 0000000..6d400ad
--- /dev/null
+++ b/modules/zookeeper/README.txt
@@ -0,0 +1,29 @@
+Apache Ignite ZooKeeper Module
+------------------------------
+
+Apache Ignite ZooKeeper module provides a TCP Discovery IP Finder that uses a ZooKeeper
+directory to locate other Ignite nodes to connect to.
+
+Importing Apache Ignite ZooKeeper Module In Maven Project
+---------------------------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add the ZooKeeper
+module dependency like this (replace '${ignite.version}' with actual Ignite version you
+are interested in):
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    ...
+    <dependencies>
+        ...
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-zookeeper</artifactId>
+            <version>${ignite.version}</version>
+        </dependency>
+        ...
+    </dependencies>
+    ...
+</project>
diff --git a/modules/zookeeper/licenses/apache-2.0.txt b/modules/zookeeper/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/zookeeper/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/package-info.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/package-info.java
new file mode 100644
index 0000000..7263710
--- /dev/null
+++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/zk/package-info.java
@@ -0,0 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Contains TCP Discovery IP Finder uses Apache ZooKeeper (ZK) to locate peer nodes.
+ */
+package org.apache.ignite.spi.discovery.tcp.ipfinder.zk;
\ No newline at end of file
diff --git a/parent/pom.xml b/parent/pom.xml
index 77dc4c9..4fd7156 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -95,10 +95,10 @@
         <paho.version>1.0.2</paho.version>
         <scala210.jline.version>2.10.4</scala210.jline.version>
         <scala210.library.version>2.10.4</scala210.library.version>
-        <scala211.library.version>2.11.2</scala211.library.version>
+        <scala211.library.version>2.11.7</scala211.library.version>
         <slf4j.version>1.7.7</slf4j.version>
         <slf4j16.version>1.6.4</slf4j16.version>
-        <spark.version>1.5.1</spark.version>
+        <spark.version>1.5.2</spark.version>
         <spring.version>4.1.0.RELEASE</spring.version>
         <spring41.osgi.feature.version>4.1.7.RELEASE_1</spring41.osgi.feature.version>
         <tomcat.version>8.0.23</tomcat.version>