Index: src/test/java/org/drools/common/LazyTMSEnablingTest.java
===================================================================
--- src/test/java/org/drools/common/LazyTMSEnablingTest.java	(revision 0)
+++ src/test/java/org/drools/common/LazyTMSEnablingTest.java	(revision 0)
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010 JBoss Inc
+ *
+ * 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.
+ */
+package org.drools.common;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.drools.RuleBaseFactory;
+import org.drools.reteoo.ObjectTypeConf;
+import org.drools.reteoo.ReteooWorkingMemory;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * <p>
+ * Verify that TMS will be lazily enabled after the first logical insert is
+ * processed.
+ * </p>
+ * 
+ * <p>
+ * This is based on the ideas <a
+ * href="http://blog.athico.com/2010/09/lazily-enabled-truth-maintenace.html">
+ * published here.</a>
+ * </p>
+ * 
+ * @author <a href="mailto:leonardo.f.gomes@gmail.com">Leonardo Gomes</a>
+ */
+public class LazyTMSEnablingTest {
+
+    private ReteooWorkingMemory wm;
+    private TruthMaintenanceSystem tms;
+
+    @Before
+    public void setUp() {
+
+        wm = (ReteooWorkingMemory) RuleBaseFactory.newRuleBase()
+                .newStatefulSession();
+
+        tms = wm.getTruthMaintenanceSystem();
+
+    }
+
+    @Test
+    public void shouldLazilyAdd() throws Exception {
+
+        final String fact1 = "logical";
+
+        wm.insert(fact1);
+
+        assertEquals(
+                "Shouldn't have anything, since no logical insert was performed.",
+                0, tms.getAssertMap().size());
+
+        final String fact2 = "logical";
+
+        wm.insertLogical(fact2);
+
+        assertEquals(
+                "Now that a logical insert was done, it should have an element.",
+                1, tms.getAssertMap().size());
+
+        // Make sure the internals are fine.
+        ObjectTypeConf typeConf = wm.getObjectTypeConfigurationRegistry()
+                .getObjectTypeConf(wm.getEntryPoint(), fact1);
+
+        assertTrue("Should have enabled TMS", typeConf.isTMSEnabled());
+
+    }
+
+    @Test
+    public void shouldEnableTMSForSpecificType() throws Exception {
+
+        final String stringFact1 = "toto";
+        final String stringFact2 = "toto";
+        final String anotherString = "tata";
+
+        final Integer intFact1 = 99;
+        final Integer intFact2 = 99;
+
+        final Double doubleFact = 77.8;
+
+        ObjectTypeConf stringTypeConf = wm.getObjectTypeConfigurationRegistry()
+                .getObjectTypeConf(wm.getEntryPoint(), stringFact1);
+
+        ObjectTypeConf intTypeConf = wm.getObjectTypeConfigurationRegistry()
+                .getObjectTypeConf(wm.getEntryPoint(), intFact1);
+
+        wm.insert(stringFact1);
+        wm.insert(anotherString);
+        wm.insert(intFact1);
+        wm.insert(doubleFact);
+
+        for (ObjectTypeConf conf : wm.getObjectTypeConfigurationRegistry()
+                .values()) {
+
+            assertFalse(
+                    "TMS shouldn't be enabled for any type, since no logical insert was done.",
+                    conf.isTMSEnabled());
+
+        }
+
+        wm.insertLogical(stringFact2);
+
+        assertTrue("Should have enabled TMS for Strings.", stringTypeConf
+                .isTMSEnabled());
+
+        assertFalse("Shouldn't have enabled TMS for Integers.", intTypeConf
+                .isTMSEnabled());
+
+        wm.insertLogical(intFact2);
+
+        assertTrue("Now it should have enabled TMS for Integers!.", intTypeConf
+                .isTMSEnabled());
+
+    }
+
+}
Index: src/test/java/org/drools/reteoo/ReteooWorkingMemoryTest.java
===================================================================
--- src/test/java/org/drools/reteoo/ReteooWorkingMemoryTest.java	(revision 35290)
+++ src/test/java/org/drools/reteoo/ReteooWorkingMemoryTest.java	(working copy)
@@ -50,10 +50,14 @@
         final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) RuleBaseFactory.newRuleBase().newStatefulSession();
         final TruthMaintenanceSystem tms = workingMemory.getTruthMaintenanceSystem();
         final String string = "test";
-        FactHandle fd = workingMemory.insert( string );
+        
+        workingMemory.insert( string );
+        
+        FactHandle fd = workingMemory.insertLogical( string );
 
         assertEquals( 1,
                       tms.getAssertMap().size() );
+        
         EqualityKey key = tms.get( string );
         assertSame( fd,
                     key.getFactHandle() );
Index: src/main/java/org/drools/common/AbstractWorkingMemory.java
===================================================================
--- src/main/java/org/drools/common/AbstractWorkingMemory.java	(revision 35290)
+++ src/main/java/org/drools/common/AbstractWorkingMemory.java	(working copy)
@@ -52,9 +52,11 @@
 import org.drools.RuleBaseConfiguration.AssertBehaviour;
 import org.drools.RuleBaseConfiguration.LogicalOverride;
 import org.drools.base.CalendarsImpl;
+import org.drools.base.ClassObjectType;
 import org.drools.base.MapGlobalResolver;
 import org.drools.concurrent.ExecutorService;
 import org.drools.concurrent.ExternalExecutorService;
+import org.drools.core.util.ObjectHashSet;
 import org.drools.event.AgendaEventListener;
 import org.drools.event.AgendaEventSupport;
 import org.drools.event.RuleBaseEventListener;
@@ -68,9 +70,10 @@
 import org.drools.reteoo.LIANodePropagation;
 import org.drools.reteoo.LeftTuple;
 import org.drools.reteoo.ObjectTypeConf;
+import org.drools.reteoo.ObjectTypeNode;
 import org.drools.reteoo.PartitionManager;
 import org.drools.reteoo.PartitionTaskManager;
-import org.drools.reteoo.ReteooWorkingMemory;
+import org.drools.reteoo.Rete;
 import org.drools.rule.Declaration;
 import org.drools.rule.EntryPoint;
 import org.drools.rule.Rule;
@@ -93,6 +96,7 @@
 import org.drools.spi.AsyncExceptionHandler;
 import org.drools.spi.FactHandleFactory;
 import org.drools.spi.GlobalResolver;
+import org.drools.spi.ObjectType;
 import org.drools.spi.PropagationContext;
 import org.drools.time.SessionClock;
 import org.drools.time.TimerService;
@@ -169,7 +173,6 @@
      */
     protected AtomicLong                                         propagationIdCounter;
 
-    private boolean                                              maintainTms;
     private boolean                                              sequential;
 
     private List                                                 liaPropagations;
@@ -319,9 +322,9 @@
 
         final RuleBaseConfiguration conf = this.ruleBase.getConfiguration();
 
-        this.maintainTms = conf.isMaintainTms();
         this.sequential = conf.isSequential();
 
+
         if ( initialFactHandle == null ) {
             this.initialFactHandle = handleFactory.newFactHandle( InitialFactImpl.getInstance(),
                                                                   null,
@@ -345,13 +348,9 @@
         timerService = TimerServiceFactory.getTimerService( this.config );
 
         this.nodeMemories = new ConcurrentNodeMemories( this.ruleBase );
+        
+        this.tms = new TruthMaintenanceSystem(this);
 
-        if ( this.maintainTms ) {
-            this.tms = new TruthMaintenanceSystem( this );
-        } else {
-            this.tms = null;
-        }
-
         this.propagationIdCounter = new AtomicLong( propagationContext );
 
         this.objectStore = new SingleThreadedObjectStore( conf,
@@ -953,6 +952,9 @@
 
             ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
                                                                           object );
+            if ( logical && !typeConf.isTMSEnabled()) {
+                enableTMS(object, typeConf);
+            }
 
             InternalFactHandle handle = null;
 
@@ -972,8 +974,8 @@
                 // check if the object already exists in the WM
                 handle = (InternalFactHandle) this.objectStore.getHandleForObject( object );
 
-                if ( this.maintainTms ) {
-
+                if ( typeConf.isTMSEnabled() ) {
+                  
                     EqualityKey key = null;
 
                     if ( handle == null ) {
@@ -1006,12 +1008,14 @@
 
                     // At this point we know the handle is null
                     if ( key == null ) {
+                      
                         handle = createHandle( object,
                                                typeConf );
 
-                        key = new EqualityKey( handle );
-                        handle.setEqualityKey( key );
+                        key = createEqualityKey(handle);
+                        
                         this.tms.put( key );
+                        
                         if ( !logical ) {
                             key.setStatus( EqualityKey.STATED );
                         } else {
@@ -1110,6 +1114,53 @@
 
     }
 
+    /** Side-effects, will add the created key to the handle. */
+    private EqualityKey createEqualityKey(InternalFactHandle handle) {
+      EqualityKey key = new EqualityKey( handle );
+      handle.setEqualityKey( key );
+      return key;
+    }
+
+    /**
+     * TMS will be automatically enabled when the first logical insert happens. 
+     * 
+     * We will take all the already asserted objects of the same type and initialize
+     * the equality map.
+     *  
+     * @param object the logically inserted object.
+     * @param conf the type's configuration.
+     */
+    private void enableTMS(Object object, ObjectTypeConf conf) {
+
+        
+        final Rete source = this.ruleBase.getRete();
+        final ClassObjectType cot = new ClassObjectType( object.getClass() );
+        final Map<ObjectType, ObjectTypeNode> map = source.getObjectTypeNodes( EntryPoint.DEFAULT );
+        final ObjectTypeNode node = map.get( cot );
+        final ObjectHashSet memory = (ObjectHashSet) this.getNodeMemory( node );
+      
+        // All objects of this type that are already there were certainly stated,
+        // since this method call happens at the first logical insert, for any given type.
+        org.drools.core.util.Iterator it = memory.iterator();
+
+        for ( Object obj = it.next(); obj != null; obj = it.next() ) {
+          
+            org.drools.core.util.ObjectHashSet.ObjectEntry holder = (org.drools.core.util.ObjectHashSet.ObjectEntry) obj; 
+    
+            InternalFactHandle handle = (InternalFactHandle) holder.getValue();
+            
+            if ( handle != null) {
+                EqualityKey key = createEqualityKey(handle);
+                key.setStatus(EqualityKey.STATED);
+                this.tms.put(key);
+            }
+        }
+      
+        // Enable TMS for this type.
+        conf.enableTMS();
+      
+    }
+
     private InternalFactHandle createHandle(final Object object,
                                             ObjectTypeConf typeConf) {
         InternalFactHandle handle;
@@ -1257,14 +1308,17 @@
                                                                                       this.entryPoint );
 
             final Object object = handle.getObject();
+            
+            final ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
+                object );
 
             this.entryPointNode.retractObject( handle,
                                                propagationContext,
-                                               this.typeConfReg.getObjectTypeConf( this.entryPoint,
-                                                                                   object ),
+                                               typeConf,
                                                this );
 
-            if ( this.maintainTms ) {
+            if ( typeConf.isTMSEnabled() ) {
+
                 // Update the equality key, which maintains a list of stated
                 // FactHandles
                 final EqualityKey key = handle.getEqualityKey();
@@ -1284,6 +1338,7 @@
                     this.tms.remove( key );
                 }
             }
+            
 
             this.workingMemoryEventSupport.fireObjectRetracted( propagationContext,
                                                                 handle,
@@ -1345,10 +1400,13 @@
             if ( ((InternalFactHandle)factHandle).isDisconnected() ) {
                 factHandle = this.objectStore.reconnect( factHandle );
             }
+            
+            final ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
+                object );
 
             // only needed if we maintain tms, but either way we must get it before we do the retract
             int status = -1;
-            if ( this.maintainTms ) {
+            if ( typeConf.isTMSEnabled() ) {
                 status = ((InternalFactHandle) factHandle).getEqualityKey().getStatus();
             }
             final InternalFactHandle handle = (InternalFactHandle) factHandle;
@@ -1373,18 +1431,19 @@
                                             object );
             }
 
-            if ( this.maintainTms ) {
-
+            if ( typeConf.isTMSEnabled() ) {
+            
                 // the hashCode and equality has changed, so we must update the
                 // EqualityKey
                 EqualityKey key = handle.getEqualityKey();
                 key.removeFactHandle( handle );
+            
 
                 // If the equality key is now empty, then remove it
                 if ( key.isEmpty() ) {
                     this.tms.remove( key );
                 }
-
+    
                 // now use an existing EqualityKey, if it exists, else create a new one
                 key = this.tms.get( object );
                 if ( key == null ) {
@@ -1394,8 +1453,9 @@
                 } else {
                     key.addFactHandle( handle );
                 }
+    
+                handle.setEqualityKey( key );
 
-                handle.setEqualityKey( key );
             }
 
             this.handleFactory.increaseFactHandleRecency( handle );
@@ -1409,9 +1469,6 @@
                                                                                       this.agenda.getDormantActivations(),
                                                                                       entryPoint );
 
-            ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
-                                                                          object );
-
             this.entryPointNode.modifyObject( handle,
                                               propagationContext,
                                               typeConf,
@@ -1474,11 +1531,11 @@
     public void removeLogicalDependencies(final Activation activation,
                                           final PropagationContext context,
                                           final Rule rule) throws FactException {
-        if ( this.maintainTms ) {
-            this.tms.removeLogicalDependencies( activation,
-                                                context,
-                                                rule );
-        }
+      
+        this.tms.removeLogicalDependencies( activation,
+                                            context,
+                                            rule );
+
     }
 
     /**
Index: src/main/java/org/drools/reteoo/ObjectTypeConf.java
===================================================================
--- src/main/java/org/drools/reteoo/ObjectTypeConf.java	(revision 35290)
+++ src/main/java/org/drools/reteoo/ObjectTypeConf.java	(working copy)
@@ -34,6 +34,15 @@
     public boolean isEvent();
     
     public boolean isDynamic();
+   
+    public TypeDeclaration getTypeDeclaration();
     
-    public TypeDeclaration getTypeDeclaration();    
+    /** Whether or not, TMS is active for this object type. */
+    public boolean isTMSEnabled();
+    
+    /**
+     * Enable TMS for this object type. 
+     * */
+    public void enableTMS();
+
 }
\ No newline at end of file
Index: src/main/java/org/drools/reteoo/FactTemplateTypeConf.java
===================================================================
--- src/main/java/org/drools/reteoo/FactTemplateTypeConf.java	(revision 35290)
+++ src/main/java/org/drools/reteoo/FactTemplateTypeConf.java	(working copy)
@@ -20,6 +20,7 @@
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.drools.RuntimeDroolsException;
 import org.drools.common.InternalRuleBase;
@@ -41,7 +42,10 @@
     private FactTemplate      factTemplate;
     private ObjectTypeNode    concreteObjectTypeNode;
     private ObjectTypeNode[]  cache;
+    
+    private boolean          tmsEnabled;
 
+
     public FactTemplateTypeConf() {
     }
 
@@ -127,5 +131,13 @@
     public boolean isDynamic() {
         return false;
     }
+    
+    public boolean isTMSEnabled() {
+        return this.tmsEnabled;
+    }
 
+    public void enableTMS() {
+        this.tmsEnabled = true;
+    }
+
 }
Index: src/main/java/org/drools/reteoo/ClassObjectTypeConf.java
===================================================================
--- src/main/java/org/drools/reteoo/ClassObjectTypeConf.java	(revision 35290)
+++ src/main/java/org/drools/reteoo/ClassObjectTypeConf.java	(working copy)
@@ -52,7 +52,10 @@
     private EntryPoint                 entryPoint;
 
     private TypeDeclaration            typeDecl;
+    
+    private boolean                   tmsEnabled;
 
+
     public ClassObjectTypeConf() {
 
     }
@@ -104,6 +107,7 @@
         shadowEnabled = stream.readBoolean();
         concreteObjectTypeNode = (ObjectTypeNode) stream.readObject();
         entryPoint = (EntryPoint) stream.readObject();
+        tmsEnabled = stream.readBoolean();
         defineShadowProxyData( cls );
     }
 
@@ -114,6 +118,7 @@
         stream.writeBoolean( shadowEnabled );
         stream.writeObject( concreteObjectTypeNode );
         stream.writeObject( entryPoint );
+        stream.writeObject(tmsEnabled);
     }
 
     public boolean isAssignableFrom(Object object) {
@@ -191,4 +196,13 @@
     public boolean isDynamic() {
         return (typeDecl != null) ? typeDecl.isDynamic() : false;
     }
+
+    public boolean isTMSEnabled() {
+        return this.tmsEnabled;
+    }
+
+    public void enableTMS() {
+        this.tmsEnabled = true;
+    }
+    
 }
