You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by ma...@apache.org on 2024/01/17 13:29:17 UTC

(incubator-kie-drools) branch main updated: [KIE-792] introducing prototypes (#5639)

This is an automated email from the ASF dual-hosted git repository.

mariofusco pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/main by this push:
     new 999a28e71d [KIE-792] introducing prototypes (#5639)
999a28e71d is described below

commit 999a28e71d2ce80410fdf99efc3caea732b93d76
Author: Mario Fusco <ma...@gmail.com>
AuthorDate: Wed Jan 17 14:29:12 2024 +0100

    [KIE-792] introducing prototypes (#5639)
    
    * [KIE-792] introducing prototype dialect
    
    * implement prototype field setting in consequence
    
    * minor refactor
    
    * rewrite prototype field access in consequence
    
    * add dialect attribute to yaml rule format + test it in quarkus extension
    
    * isolate prototypes in their own module
    
    * introduce new public API for prototypes
    
    * get rid of fact templates
    
    * turn prototype dialect into a KieBase option
    
    * implement access of map values via field notation in the mvel compiler
---
 bom/drools-bom/pom.xml                             |  18 +
 .../java/org/drools/base/base/ClassObjectType.java |   2 +-
 .../main/java/org/drools/base/base/ObjectType.java |   2 +-
 .../main/java/org/drools/base/base/ValueType.java  |   8 +-
 .../base/definitions/InternalKnowledgePackage.java |   6 +-
 .../definitions/impl/KnowledgePackageImpl.java     |  25 +-
 .../org/drools/base/facttemplates/FactImpl.java    |  89 ----
 .../drools/base/facttemplates/FactTemplate.java    |  63 ---
 .../base/facttemplates/FactTemplateImpl.java       | 150 ------
 .../drools/base/facttemplates/FieldTemplate.java   |  29 --
 .../base/facttemplates/FieldTemplateImpl.java      |  87 ----
 .../PrototypeFieldExtractor.java}                  |  85 ++--
 .../PrototypeObjectType.java}                      |  70 ++-
 .../drools/base/reteoo/PropertySpecificUtil.java   |  10 +-
 .../src/main/java/org/drools/base/rule/From.java   |   4 +-
 .../java/org/drools/base/rule/TypeDeclaration.java |  32 +-
 .../drools/base/rule/accessor/GlobalExtractor.java |   6 +-
 .../base/rule/accessor/PatternExtractor.java       |   6 +-
 .../builder/impl/DroolsAssemblerContextImpl.java   |   2 +-
 .../KnowledgeBuilderRulesConfigurationImpl.java    |  18 +-
 .../builder/impl/TypeDeclarationManagerImpl.java   |   2 +-
 .../drools/compiler/compiler/BoundIdentifiers.java |   4 +-
 .../compiler/compiler/FactTemplateError.java       |  73 ---
 .../compiler/compiler/FieldTemplateError.java      |  72 ---
 .../kie/builder/impl/AbstractKieModule.java        |  13 +-
 .../compiler/kproject/models/KieBaseModelImpl.java |  20 +-
 .../compiler/rule/builder/PatternBuilder.java      |  33 +-
 .../org/drools/core/RuleBaseConfiguration.java     |  40 +-
 .../common/ObjectTypeConfigurationRegistry.java    |  15 +-
 .../org/drools/core/phreak/PropagationEntry.java   |   6 +-
 ...emplateTypeConf.java => PrototypeTypeConf.java} |  44 +-
 .../FactTemplateFieldExtractorTest.java            | 108 ----
 .../core/facttemplates/FactTemplateTest.java       | 120 -----
 .../src/test/resources/expected/test1.yml          |   1 +
 .../src/test/resources/expected/test2.drl.txt      |   1 +
 .../integration/tests/ProgrammaticProjectTest.java |  52 +-
 .../org/drools/drlonyaml/model/DrlPackage.java     |  13 +-
 .../src/main/resources/drlonyaml-schema.json       |   3 +
 .../src/main/resources/drl.ftl                     |   1 +
 .../impact/analysis/parser/impl/PackageParser.java |   4 +-
 .../impact/analysis/parser/impl/RhsParser.java     |   6 +-
 .../kiesession/entrypoints/NamedEntryPoint.java    |  31 +-
 .../org/drools/model/PrototypeFactFactory.java     |  51 --
 .../src/main/java/org/drools/model/Variable.java   |   4 +
 drools-model/drools-model-codegen/pom.xml          |   4 +
 .../model/codegen/execmodel/PackageModel.java      |  48 +-
 .../codegen/execmodel/generator/AggregateKey.java  |  30 +-
 .../execmodel/generator/BoxedParameters.java       |  48 +-
 .../codegen/execmodel/generator/Consequence.java   |  23 +-
 .../execmodel/generator/DeclarationSpec.java       | 153 +-----
 .../codegen/execmodel/generator/DrlxParseUtil.java |   6 +-
 .../execmodel/generator/DslMethodNames.java        |  12 +
 .../execmodel/generator/ModelGenerator.java        |  59 +--
 .../execmodel/generator/OOPathExprGenerator.java   |   2 +-
 .../generator/PrototypeDeclarationSpec.java        |  82 ++++
 .../execmodel/generator/QueryGenerator.java        |   9 +-
 .../codegen/execmodel/generator/RuleContext.java   | 103 ++--
 ...larationSpec.java => TypedDeclarationSpec.java} |  92 +++-
 .../generator/drlxparse/ConstraintExpression.java  |   2 +-
 .../generator/drlxparse/ConstraintParser.java      |  10 +-
 .../expression/AbstractExpressionBuilder.java      |   2 +-
 .../generator/expressiontyper/ExpressionTyper.java |  20 +-
 .../execmodel/generator/visitor/FromVisitor.java   |   6 +-
 .../visitor/accumulate/AccumulateInline.java       |  10 +-
 .../visitor/accumulate/AccumulateVisitor.java      |  42 +-
 .../visitor/accumulate/GroupByVisitor.java         |   4 +-
 .../visitor/accumulate/LegacyAccumulate.java       |   2 +-
 .../{PatternDSL.java => ClassPatternDSL.java}      | 214 +++++---
 .../visitor/pattern/ConstraintOOPath.java          |   6 +-
 .../pattern/PatternAccumulateConstraint.java       |   2 +-
 .../pattern/PatternConstraintParseResult.java      |  24 +-
 .../generator/visitor/pattern/PatternDSL.java      | 312 +-----------
 .../visitor/pattern/PatternDSLPattern.java         | 136 ------
 .../generator/visitor/pattern/PatternVisitor.java  |   5 +-
 .../visitor/pattern/PrototypePatternDSL.java       | 132 +++++
 .../processors/ModelMainCompilationPhase.java      |  12 +-
 .../KogitoKnowledgeBuilderConfigurationImpl.java   |  53 --
 .../{FactTemplateTest.java => PrototypeTest.java}  | 544 ++++++++++-----------
 .../codegen/execmodel/PrototypesAllowedTest.java   | 215 ++++++++
 .../execmodel/SegmentPrototypeExpressionTest.java  |  23 +-
 .../execmodel/generator/ExpressionTyperTest.java   |  18 +-
 .../drools/modelcompiler/KiePackagesBuilder.java   |  17 +-
 .../org/drools/modelcompiler/PrototypeService.java |  50 ++
 .../modelcompiler/facttemplate/FactFactory.java    |  82 ----
 .../facttemplate/PrototypeFactFactoryImpl.java     |  38 --
 .../services/org.drools.model.PrototypeFactFactory |   1 -
 drools-model/drools-model-prototype/pom.xml        |  50 ++
 .../org/drools/model/prototype}/PrototypeDSL.java  | 117 ++---
 .../model/prototype}/PrototypeExpression.java      |  42 +-
 .../drools/model/prototype}/PrototypeVariable.java |  13 +-
 .../model/prototype/impl}/HashMapEventImpl.java    |  22 +-
 .../model/prototype/impl}/HashMapFactImpl.java     |  31 +-
 .../model/prototype/impl/PrototypeBuilderImpl.java |  82 ++++
 .../model/prototype/impl/PrototypeEventImpl.java   |  21 +-
 .../model/prototype/impl/PrototypeFactImpl.java    |  23 +-
 .../model/prototype}/impl/PrototypeImpl.java       |  69 +--
 .../model/prototype/impl/PrototypeServiceImpl.java |  44 ++
 .../prototype}/impl/PrototypeVariableImpl.java     |  15 +-
 .../org.drools.modelcompiler.PrototypeService      |   1 +
 .../org.kie.api.prototype.PrototypeBuilder$Creator |   1 +
 .../prototype/PrototypeFieldExtractorTest.java     |  86 ++++
 .../java/org/drools/mvelcompiler/LHSPhase.java     |  10 +-
 .../drools/mvelcompiler/PreprocessCompiler.java    |  44 +-
 .../java/org/drools/mvelcompiler/RHSPhase.java     |  15 +-
 .../ast/{MapPutExprT.java => MapGetExprT.java}     |  25 +-
 .../org/drools/mvelcompiler/ast/MapPutExprT.java   |  16 +-
 .../org/drools/mvelcompiler/util/TypeUtils.java    |  19 +
 .../org/drools/mvelcompiler/MvelCompilerTest.java  |  21 +
 .../mvelcompiler/PreprocessCompilerTest.java       |   3 +-
 drools-model/pom.xml                               |   3 +-
 .../org/drools/mvel/MVELKnowledgePackageImpl.java  |   4 +-
 .../org/drools/quarkus/test/TestableResource.java  |  20 +-
 .../src/main/resources/META-INF/kmodule.xml        |   7 +-
 .../src/main/resources/application.properties      |  20 +
 .../org/drools/prototype/CanDrink.drl.yaml         |  22 +
 .../java/org/drools/quarkus/test/RuntimeTest.java  |  32 +-
 .../deployment/DroolsQuarkusResourceUtils.java     |  21 +-
 .../test/ReliabilityCepOnceAfterTest.java          |  49 +-
 .../test/ReliabilityCepOnceWithinTest.java         |  35 +-
 .../test/ReliabilityCepTimeWindowTest.java         |  14 +-
 .../test/ReliabilityCepTimedOutTest.java           |  63 ++-
 .../reliability/test/ReliabilityTestBasics.java    |  36 +-
 .../test/proto/HashMapEventImplAdaptor.java        |  12 +-
 .../reliability/test/util/PrototypeUtils.java      |  32 +-
 .../conf/KnowledgeBaseConfigurationTest.java       |  20 +
 .../drools/mvel/integrationtests/Misc2Test.java    |  29 --
 .../java/org/drools/mvel/rule/PatternTest.java     |  46 +-
 .../impl/TraitKnowledgePackageImpl.java            |   4 +-
 .../xml/support/converters/KBaseConverter.java     |   9 +
 .../org/kie/api/builder/model/KieBaseModel.java    |  12 +
 .../java/org/kie/api/conf/PrototypesOption.java    |  56 +++
 .../java/org/kie/api/prototype}/Prototype.java     |  21 +-
 .../org/kie/api/prototype/PrototypeBuilder.java    |  50 ++
 .../java/org/kie/api/prototype/PrototypeEvent.java |   9 +-
 .../kie/api/prototype/PrototypeEventInstance.java  |   6 +-
 .../java/org/kie/api/prototype/PrototypeFact.java  |   8 +-
 .../kie/api/prototype/PrototypeFactInstance.java   |  11 +-
 kie-api/src/main/resources/org/kie/api/kmodule.xsd |   8 +
 .../java/org/kie/internal/utils/KieHelper.java     |  26 +-
 139 files changed, 2596 insertions(+), 2941 deletions(-)

diff --git a/bom/drools-bom/pom.xml b/bom/drools-bom/pom.xml
index 746b669770..f718a910cf 100644
--- a/bom/drools-bom/pom.xml
+++ b/bom/drools-bom/pom.xml
@@ -630,6 +630,24 @@
         <type>test-jar</type>
         <scope>test</scope>
       </dependency>
+      <dependency>
+        <groupId>org.drools</groupId>
+        <artifactId>drools-model-prototype</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.drools</groupId>
+        <artifactId>drools-model-prototype</artifactId>
+        <version>${project.version}</version>
+        <classifier>sources</classifier>
+      </dependency>
+      <dependency>
+        <groupId>org.drools</groupId>
+        <artifactId>drools-model-prototype</artifactId>
+        <version>${project.version}</version>
+        <type>test-jar</type>
+        <scope>test</scope>
+      </dependency>
 
       <!-- Quarkus Extension -->
       <dependency>
diff --git a/drools-base/src/main/java/org/drools/base/base/ClassObjectType.java b/drools-base/src/main/java/org/drools/base/base/ClassObjectType.java
index 150fad3d6e..5b674f2398 100644
--- a/drools-base/src/main/java/org/drools/base/base/ClassObjectType.java
+++ b/drools-base/src/main/java/org/drools/base/base/ClassObjectType.java
@@ -185,7 +185,7 @@ public class ClassObjectType
     }
 
     @Override
-    public boolean isTemplate() {
+    public boolean isPrototype() {
         return false;
     }
 
diff --git a/drools-base/src/main/java/org/drools/base/base/ObjectType.java b/drools-base/src/main/java/org/drools/base/base/ObjectType.java
index 03cdd4f648..49f13d78c8 100644
--- a/drools-base/src/main/java/org/drools/base/base/ObjectType.java
+++ b/drools-base/src/main/java/org/drools/base/base/ObjectType.java
@@ -48,5 +48,5 @@ public interface ObjectType
 
     boolean hasField(String name);
 
-    boolean isTemplate();
+    boolean isPrototype();
 }
diff --git a/drools-base/src/main/java/org/drools/base/base/ValueType.java b/drools-base/src/main/java/org/drools/base/base/ValueType.java
index e3edc67f65..63bb006991 100644
--- a/drools-base/src/main/java/org/drools/base/base/ValueType.java
+++ b/drools-base/src/main/java/org/drools/base/base/ValueType.java
@@ -27,8 +27,8 @@ import java.util.function.Function;
 
 import org.drools.base.factmodel.traits.Thing;
 import org.drools.base.factmodel.traits.Trait;
-import org.drools.base.facttemplates.FactTemplate;
 import org.drools.util.CoercionUtil;
+import org.kie.api.prototype.Prototype;
 import org.kie.api.runtime.rule.EventHandle;
 
 public enum ValueType {
@@ -65,7 +65,7 @@ public enum ValueType {
     ARRAY_TYPE( "Array", Object[].class, SimpleValueType.LIST ),
     STRING_TYPE( "String", String.class, SimpleValueType.STRING, CoercionUtil::coerceToString ),
     OBJECT_TYPE( "Object", Object.class, SimpleValueType.OBJECT ),
-    FACTTEMPLATE_TYPE( "FactTemplate", FactTemplate.class, SimpleValueType.UNKNOWN ),
+    PROTOTYPE_TYPE("Prototype", Prototype.class, SimpleValueType.UNKNOWN ),
 
     EVENT_TYPE("Event", EventHandle.class, SimpleValueType.OBJECT ),
     QUERY_TYPE("Query", DroolsQuery.class, SimpleValueType.OBJECT ),
@@ -141,8 +141,8 @@ public enum ValueType {
         }
 
         // primitives
-        if ( clazz == FactTemplate.class ) {
-            return ValueType.FACTTEMPLATE_TYPE;
+        if ( clazz == Prototype.class ) {
+            return ValueType.PROTOTYPE_TYPE;
         } else if ( clazz == DroolsQuery.class ) {
             return ValueType.QUERY_TYPE;
         } else if ( clazz == Character.TYPE ) {
diff --git a/drools-base/src/main/java/org/drools/base/definitions/InternalKnowledgePackage.java b/drools-base/src/main/java/org/drools/base/definitions/InternalKnowledgePackage.java
index 19cd8c5ce5..f2953066e1 100644
--- a/drools-base/src/main/java/org/drools/base/definitions/InternalKnowledgePackage.java
+++ b/drools-base/src/main/java/org/drools/base/definitions/InternalKnowledgePackage.java
@@ -30,7 +30,6 @@ import org.drools.base.RuleBase;
 import org.drools.base.base.AcceptsClassObjectType;
 import org.drools.base.base.ObjectType;
 import org.drools.base.definitions.rule.impl.RuleImpl;
-import org.drools.base.facttemplates.FactTemplate;
 import org.drools.base.rule.DialectRuntimeRegistry;
 import org.drools.base.rule.Function;
 import org.drools.base.rule.ImportDeclaration;
@@ -44,6 +43,7 @@ import org.kie.api.definition.KiePackage;
 import org.kie.api.definition.process.Process;
 import org.kie.api.definition.type.FactType;
 import org.kie.api.io.Resource;
+import org.kie.api.prototype.Prototype;
 import org.kie.api.runtime.rule.AccumulateFunction;
 import org.kie.internal.builder.KnowledgeBuilderResult;
 
@@ -98,7 +98,7 @@ public interface InternalKnowledgePackage extends KiePackage,
 
     void addTypeDeclaration(TypeDeclaration typeDecl);
 
-    void addFactTemplate(FactTemplate factTemplate);
+    void addPrototype(Prototype prototype);
 
     void addImport(ImportDeclaration importDecl);
 
@@ -141,7 +141,7 @@ public interface InternalKnowledgePackage extends KiePackage,
 
     TypeDeclaration getTypeDeclaration(String type);
 
-    FactTemplate getFactTemplate(String name);
+    Prototype getPrototype(String name);
 
     ClassLoader getPackageClassLoader();
 
diff --git a/drools-base/src/main/java/org/drools/base/definitions/impl/KnowledgePackageImpl.java b/drools-base/src/main/java/org/drools/base/definitions/impl/KnowledgePackageImpl.java
index f2dc9e3b3f..b96b3cbb05 100644
--- a/drools-base/src/main/java/org/drools/base/definitions/impl/KnowledgePackageImpl.java
+++ b/drools-base/src/main/java/org/drools/base/definitions/impl/KnowledgePackageImpl.java
@@ -45,7 +45,6 @@ import org.drools.base.definitions.ProcessPackage;
 import org.drools.base.definitions.ResourceTypePackageRegistry;
 import org.drools.base.definitions.rule.impl.GlobalImpl;
 import org.drools.base.definitions.rule.impl.RuleImpl;
-import org.drools.base.facttemplates.FactTemplate;
 import org.drools.base.rule.DialectRuntimeData;
 import org.drools.base.rule.DialectRuntimeRegistry;
 import org.drools.base.rule.DuplicateRuleNameException;
@@ -68,6 +67,7 @@ import org.kie.api.definition.rule.Rule;
 import org.kie.api.definition.type.FactType;
 import org.kie.api.io.Resource;
 import org.kie.api.io.ResourceType;
+import org.kie.api.prototype.Prototype;
 import org.kie.api.runtime.rule.AccumulateFunction;
 
 public class KnowledgePackageImpl
@@ -103,7 +103,7 @@ public class KnowledgePackageImpl
 
     protected Map<String, Type> globals;
 
-    protected Map<String, FactTemplate> factTemplates;
+    protected Map<String, Prototype> prototypes;
 
     protected DialectRuntimeRegistry dialectRuntimeRegistry;
 
@@ -151,7 +151,7 @@ public class KnowledgePackageImpl
         this.accumulateFunctions = Collections.emptyMap();
         this.staticImports = Collections.emptySet();
         this.globals = Collections.emptyMap();
-        this.factTemplates = Collections.emptyMap();
+        this.prototypes = Collections.emptyMap();
         this.functions = Collections.emptyMap();
         this.dialectRuntimeRegistry = new DialectRuntimeRegistry();
         this.entryPointsIds = Collections.emptySet();
@@ -243,7 +243,7 @@ public class KnowledgePackageImpl
             out.writeObject(this.staticImports);
             out.writeObject(this.functions);
             out.writeObject(this.accumulateFunctions);
-            out.writeObject(this.factTemplates);
+            out.writeObject(this.prototypes);
             out.writeObject(this.globals);
             out.writeBoolean(this.valid);
             out.writeBoolean(this.needStreamMode);
@@ -289,7 +289,7 @@ public class KnowledgePackageImpl
         this.staticImports = (Set) in.readObject();
         this.functions = (Map<String, Function>) in.readObject();
         this.accumulateFunctions = (Map<String, AccumulateFunction>) in.readObject();
-        this.factTemplates = (Map) in.readObject();
+        this.prototypes = (Map) in.readObject();
         this.globals = (Map<String, Type>) in.readObject();
         this.valid = in.readBoolean();
         this.needStreamMode = in.readBoolean();
@@ -445,17 +445,16 @@ public class KnowledgePackageImpl
     }
 
     @Override
-    public FactTemplate getFactTemplate(final String name) {
-        return this.factTemplates.get(name);
+    public Prototype getPrototype(final String name) {
+        return this.prototypes.get(name);
     }
 
     @Override
-    public void addFactTemplate(final FactTemplate factTemplate) {
-        if (this.factTemplates == Collections.EMPTY_MAP) {
-            this.factTemplates = new HashMap<>(1);
+    public void addPrototype(final Prototype prototype) {
+        if (this.prototypes == Collections.EMPTY_MAP) {
+            this.prototypes = new HashMap<>(1);
         }
-        this.factTemplates.put(factTemplate.getName(),
-                               factTemplate);
+        this.prototypes.put(prototype.getName(), prototype);
     }
 
     /**
@@ -586,7 +585,7 @@ public class KnowledgePackageImpl
         this.accumulateFunctions.clear();
         this.staticImports.clear();
         this.globals.clear();
-        this.factTemplates.clear();
+        this.prototypes.clear();
         this.typeDeclarations.clear();
         this.windowDeclarations.clear();
     }
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FactImpl.java b/drools-base/src/main/java/org/drools/base/facttemplates/FactImpl.java
deleted file mode 100644
index b081e5817a..0000000000
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FactImpl.java
+++ /dev/null
@@ -1,89 +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.drools.base.facttemplates;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-//import woolfel.engine.rule.Rule;
-
-public class FactImpl implements Fact, Externalizable {
-
-    private FactTemplate factTemplate = null;
-    private Map<String, Object> values = new HashMap<>();
-
-    public FactImpl() {
-    }
-
-    public FactImpl(final FactTemplate template) {
-        this.factTemplate = template;
-    }
-
-    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        factTemplate    = (FactTemplate)in.readObject();
-        values          = (Map<String, Object>)in.readObject();
-    }
-
-    public void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject(factTemplate);
-        out.writeObject(values);
-    }
-
-    public Object get(final String name) {
-        return this.values.get( name );
-    }
-
-    public void set(final String name, final Object value) {
-        this.values.put( name, value );
-    }
-
-    /**
-     * Return the deftemplate for the fact
-     */
-    public FactTemplate getFactTemplate() {
-        return this.factTemplate;
-    }
-
-    @Override
-    public Map<String, Object> asMap() {
-        return values;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        FactImpl fact = (FactImpl) o;
-        return factTemplate.equals(fact.factTemplate) && values.equals(fact.values);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(factTemplate, values);
-    }
-}
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplate.java b/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplate.java
deleted file mode 100644
index 4b0ffaed98..0000000000
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplate.java
+++ /dev/null
@@ -1,63 +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.drools.base.facttemplates;
-
-import java.io.Externalizable;
-import java.util.Collection;
-
-import org.drools.base.definitions.InternalKnowledgePackage;
-
-
-public interface FactTemplate
-    extends
-    Externalizable {
-
-    InternalKnowledgePackage getPackage();
-
-    /**
-     * The name of the template may be the fully qualified
-     * class name, or an alias.
-     * @return
-     */
-    String getName();
-
-    /**
-     * templates may have 1 or more slots. A slot is a named
-     * pattern with a specific type of value.
-     * @return
-     */
-    int getNumberOfFields();
-
-    Collection<String> getFieldNames();
-
-    /**
-     * Return the slot with the String name
-     * @return
-     */
-    FieldTemplate getFieldTemplate(String name);
-
-    /**
-     * Get the pattern index with the given name
-     * @param name
-     * @return
-     */
-    int getFieldTemplateIndex(String name);
-
-    Fact createFact();
-}
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateImpl.java b/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateImpl.java
deleted file mode 100644
index 07622df7cf..0000000000
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateImpl.java
+++ /dev/null
@@ -1,150 +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.drools.base.facttemplates;
-
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Objects;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.drools.base.definitions.InternalKnowledgePackage;
-
-
-public class FactTemplateImpl implements FactTemplate {
-
-    private InternalKnowledgePackage pkg;
-    private String name;
-    private SortedMap<String, FieldTemplate> fields = new TreeMap<>();
-
-    public FactTemplateImpl() {
-        
-    }
-
-    public FactTemplateImpl(final InternalKnowledgePackage pkg,
-                            final String name,
-                            final FieldTemplate... fields) {
-        this.pkg = pkg;
-        this.name = name;
-        this.pkg.addFactTemplate( this );
-
-        if (fields != null && fields.length > 0) {
-            this.fields = new TreeMap<>();
-            for (FieldTemplate field : fields) {
-                this.fields.put(field.getName(), field);
-            }
-        } else {
-            this.fields = Collections.emptySortedMap();
-        }
-    }
-
-    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        pkg     = (InternalKnowledgePackage)in.readObject();
-        name    = (String)in.readObject();
-        fields  = (SortedMap<String, FieldTemplate>)in.readObject();
-    }
-
-    public void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject(pkg);
-        out.writeObject(name);
-        out.writeObject(fields);
-    }
-
-    public InternalKnowledgePackage getPackage() {
-        return this.pkg;
-    }
-
-    /**
-     * the template name is an alias for an object
-     */
-    public String getName() {
-        return this.name;
-    }
-
-    /**
-     * Return the number of slots in the deftemplate
-     * @return
-     */
-    public int getNumberOfFields() {
-        return this.fields.size();
-    }
-
-    /**
-     * Return all the slots
-     * @return
-     */
-    public Collection<String> getFieldNames() {
-        return this.fields.keySet();
-    }
-
-    /**
-     * A convienance method for finding the slot matching
-     * the String name.
-     * @param name
-     * @return
-     */
-    public FieldTemplate getFieldTemplate(final String name) {
-        return this.fields.get(name);
-    }
-
-    /**
-     * Look up the pattern index of the slot
-     */
-    public int getFieldTemplateIndex(final String name) {
-        int i = 0;
-        for ( String field : fields.keySet() ) {
-            if ( field.equals( name ) ) {
-                return i;
-            }
-            i++;
-        }
-        return -1;
-    }
-
-    /**
-     * Method takes a list of Slots and creates a deffact from it.
-     */
-    public Fact createFact() {
-        return new FactImpl( this );
-    }
-
-    public String toString() {
-        return "FactTemplate of: " + this.name;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        FactTemplateImpl that = (FactTemplateImpl) o;
-        return pkg.getName().equals(that.pkg.getName()) && name.equals(that.name) && fields.equals(that.fields);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(pkg.getName(), name, fields);
-    }
-}
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FieldTemplate.java b/drools-base/src/main/java/org/drools/base/facttemplates/FieldTemplate.java
deleted file mode 100644
index fd77a04de1..0000000000
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FieldTemplate.java
+++ /dev/null
@@ -1,29 +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.drools.base.facttemplates;
-
-import org.drools.base.base.ValueType;
-
-public interface FieldTemplate {
-
-    String getName();
-
-    ValueType getValueType();
-
-}
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FieldTemplateImpl.java b/drools-base/src/main/java/org/drools/base/facttemplates/FieldTemplateImpl.java
deleted file mode 100644
index e0de97e9bf..0000000000
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FieldTemplateImpl.java
+++ /dev/null
@@ -1,87 +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.drools.base.facttemplates;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-
-import org.drools.base.base.ValueType;
-
-public class FieldTemplateImpl implements FieldTemplate, Externalizable {
-
-    private static final long serialVersionUID = 510l;
-
-    private String      name;
-    private ValueType   valueType;
-
-    public FieldTemplateImpl() {
-
-    }
-
-    public FieldTemplateImpl(String name, Class clazz) {
-        this.name = name;
-        this.valueType = clazz != null ? ValueType.OBJECT_TYPE : ValueType.determineValueType( clazz );
-    }
-
-    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        name    = (String)in.readObject();
-        valueType   = (ValueType)in.readObject();
-        if (valueType != null) {
-            valueType   = ValueType.determineValueType(valueType.getClassType());
-        }
-    }
-
-    public void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject(name);
-        out.writeObject(valueType);
-    }
-
-    public String getName() {
-        return this.name;
-    }
-
-    public ValueType getValueType() {
-        return this.valueType;
-    }
-
-    public int hashCode() {
-        final int PRIME = 31;
-        int result = 1;
-        result = PRIME * result + this.name.hashCode();
-        result = PRIME * result + this.valueType.hashCode();
-        return result;
-    }
-
-    public boolean equals(final Object object) {
-        if ( this == object ) {
-            return true;
-        }
-
-        if ( object == null || getClass() != object.getClass() ) {
-            return false;
-        }
-
-        final FieldTemplateImpl other = (FieldTemplateImpl) object;
-
-        return this.name.equals( other.name ) && this.valueType.equals( other.valueType );
-    }
-
-}
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateFieldExtractor.java b/drools-base/src/main/java/org/drools/base/prototype/PrototypeFieldExtractor.java
similarity index 58%
rename from drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateFieldExtractor.java
rename to drools-base/src/main/java/org/drools/base/prototype/PrototypeFieldExtractor.java
index bbf498076d..4a6732fd58 100644
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateFieldExtractor.java
+++ b/drools-base/src/main/java/org/drools/base/prototype/PrototypeFieldExtractor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.base.facttemplates;
+package org.drools.base.prototype;
 
 import java.io.Externalizable;
 import java.io.IOException;
@@ -28,47 +28,45 @@ import org.drools.base.base.ValueResolver;
 import org.drools.base.base.ValueType;
 import org.drools.base.rule.accessor.ReadAccessor;
 import org.drools.util.ClassUtils;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
 
-public class FactTemplateFieldExtractor
-    implements
-    Externalizable,
-        ReadAccessor {
+public class PrototypeFieldExtractor implements Externalizable, ReadAccessor {
 
     private static final long serialVersionUID = 510l;
-    private FactTemplate factTemplate;
+    private Prototype prototype;
     private String fieldName;
     private int fieldIndex;
 
-    public FactTemplateFieldExtractor() {
+    public PrototypeFieldExtractor() {
 
     }
 
-    public FactTemplateFieldExtractor(FactTemplate factTemplate, String fieldName) {
-        this.factTemplate = factTemplate;
+    public PrototypeFieldExtractor(Prototype prototype, String fieldName) {
+        this.prototype = prototype;
         this.fieldName = fieldName;
-        this.fieldIndex = factTemplate.getFieldTemplateIndex(fieldName);
+        this.fieldIndex = prototype.getFieldIndex(fieldName);
     }
 
     public void readExternal(ObjectInput in) throws IOException,
                                             ClassNotFoundException {
-        factTemplate = (FactTemplate) in.readObject();
+        prototype = (Prototype) in.readObject();
         fieldName = in.readUTF();
         fieldIndex = in.readInt();
     }
 
     public void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject( factTemplate );
+        out.writeObject( prototype );
         out.writeUTF( fieldName );
         out.writeInt( fieldIndex );
     }
 
     public ValueType getValueType() {
-        return this.factTemplate.getFieldTemplate( this.fieldName ).getValueType();
+        return ValueType.determineValueType(getExtractToClass());
     }
 
-    public Object getValue(ValueResolver valueResolver,
-                           final Object object) {
-        return ((Fact) object).get( this.fieldName );
+    public Object getValue(ValueResolver valueResolver, final Object object) {
+        return ((PrototypeFactInstance) object).get(this.fieldName );
     }
 
     public int getIndex() {
@@ -76,51 +74,44 @@ public class FactTemplateFieldExtractor
     }
 
     public Class getExtractToClass() {
-        return this.factTemplate.getFieldTemplate( fieldName ).getValueType().getClassType();
+        Prototype.Field field = this.prototype.getField( fieldName );
+        return field != null ? field.getClass() : Object.class;
     }
 
     public String getExtractToClassName() {
         return ClassUtils.canonicalName( getExtractToClass() );
     }
 
-    public boolean getBooleanValue(ValueResolver valueResolver,
-                                   final Object object) {
-        return ((Boolean) ((Fact) object).get( fieldName )).booleanValue();
+    public boolean getBooleanValue(ValueResolver valueResolver, Object object) {
+        return (Boolean) ((PrototypeFactInstance) object).get(fieldName);
     }
 
-    public byte getByteValue(ValueResolver valueResolver,
-                             final Object object) {
-        return ((Number) ((Fact) object).get( fieldName )).byteValue();
+    public byte getByteValue(ValueResolver valueResolver, Object object) {
+        return ((Number) ((PrototypeFactInstance) object).get( fieldName )).byteValue();
     }
 
-    public char getCharValue(ValueResolver valueResolver,
-                             final Object object) {
-        return ((Character) ((Fact) object).get( fieldName )).charValue();
+    public char getCharValue(ValueResolver valueResolver, Object object) {
+        return (Character) ((PrototypeFactInstance) object).get(fieldName);
     }
 
-    public double getDoubleValue(ValueResolver valueResolver,
-                                 final Object object) {
-        return ((Number) ((Fact) object).get( fieldName )).doubleValue();
+    public double getDoubleValue(ValueResolver valueResolver, Object object) {
+        return ((Number) ((PrototypeFactInstance) object).get( fieldName )).doubleValue();
     }
 
-    public float getFloatValue(ValueResolver valueResolver,
-                               final Object object) {
-        return ((Number) ((Fact) object).get( fieldName )).floatValue();
+    public float getFloatValue(ValueResolver valueResolver, Object object) {
+        return ((Number) ((PrototypeFactInstance) object).get( fieldName )).floatValue();
     }
 
-    public int getIntValue(ValueResolver valueResolver,
-                           final Object object) {
-        return ((Number) ((Fact) object).get( fieldName )).intValue();
+    public int getIntValue(ValueResolver valueResolver, Object object) {
+        return ((Number) ((PrototypeFactInstance) object).get( fieldName )).intValue();
     }
 
-    public long getLongValue(ValueResolver valueResolver,
-                             final Object object) {
-        return ((Number) ((Fact) object).get( fieldName )).longValue();
+    public long getLongValue(ValueResolver valueResolver, Object object) {
+        return ((Number) ((PrototypeFactInstance) object).get( fieldName )).longValue();
     }
 
-    public short getShortValue(ValueResolver valueResolver,
-                               final Object object) {
-        return ((Number) ((Fact) object).get( fieldName )).shortValue();
+    public short getShortValue(ValueResolver valueResolver, Object object) {
+        return ((Number) ((PrototypeFactInstance) object).get( fieldName )).shortValue();
     }
 
     public Method getNativeReadMethod() {
@@ -150,7 +141,7 @@ public class FactTemplateFieldExtractor
     }
 
     public boolean isNullValue(ValueResolver valueResolver, Object object) {
-        return ((Fact) object).get( this.fieldName ) == null;
+        return ((PrototypeFactInstance) object).get( this.fieldName ) == null;
     }
 
     public int getHashCode(Object object) {
@@ -169,7 +160,7 @@ public class FactTemplateFieldExtractor
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((factTemplate == null) ? 0 : factTemplate.hashCode());
+        result = prime * result + ((prototype == null) ? 0 : prototype.hashCode());
         result = prime * result + fieldIndex;
         return result;
     }
@@ -185,13 +176,13 @@ public class FactTemplateFieldExtractor
         if ( getClass() != obj.getClass() ) {
             return false;
         }
-        FactTemplateFieldExtractor other = (FactTemplateFieldExtractor) obj;
+        PrototypeFieldExtractor other = (PrototypeFieldExtractor) obj;
         
-        if ( factTemplate == null ) {
-            if ( other.factTemplate != null ) {
+        if ( prototype == null ) {
+            if ( other.prototype != null ) {
             return false;
             }
-        } else if ( !factTemplate.equals( other.factTemplate ) ) {
+        } else if ( !prototype.equals( other.prototype ) ) {
             return false;
         }
         
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateObjectType.java b/drools-base/src/main/java/org/drools/base/prototype/PrototypeObjectType.java
similarity index 63%
rename from drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateObjectType.java
rename to drools-base/src/main/java/org/drools/base/prototype/PrototypeObjectType.java
index cd782deed0..d62088f18e 100644
--- a/drools-base/src/main/java/org/drools/base/facttemplates/FactTemplateObjectType.java
+++ b/drools-base/src/main/java/org/drools/base/prototype/PrototypeObjectType.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.base.facttemplates;
+package org.drools.base.prototype;
 
 import java.io.IOException;
 import java.io.ObjectInput;
@@ -25,51 +25,39 @@ import java.util.Collection;
 
 import org.drools.base.base.ObjectType;
 import org.drools.base.base.ValueType;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
 
-public class FactTemplateObjectType
-    implements
-    ObjectType {
+public class PrototypeObjectType implements ObjectType {
 
+    protected Prototype prototype;
 
-    private static final long serialVersionUID = 510l;
-
-    /** FieldTemplate. */
-    protected FactTemplate    factTemplate;
-
-    private boolean           isEvent;
+    private boolean isEvent;
 
     // ------------------------------------------------------------
     // Constructors
     // ------------------------------------------------------------
-    public FactTemplateObjectType() {
+    public PrototypeObjectType() {
 
     }
 
-    public FactTemplateObjectType(final FactTemplate factTemplate) {
-        this.factTemplate = factTemplate;
+    public PrototypeObjectType(Prototype prototype) {
+        this.prototype = prototype;
     }
 
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        factTemplate    = (FactTemplate)in.readObject();
-        isEvent         = in.readBoolean();
+        prototype    = (Prototype)in.readObject();
+        isEvent      = in.readBoolean();
     }
 
     public void writeExternal(ObjectOutput out) throws IOException {
-        out.writeObject(factTemplate);
+        out.writeObject(prototype);
         out.writeBoolean(isEvent);
 
     }
-    // ------------------------------------------------------------
-    // Instance methods
-    // ------------------------------------------------------------
 
-    /**
-     * Return the Fact Template.
-     *
-     * @return The Fact Template
-     */
-    public FactTemplate getFactTemplate() {
-        return this.factTemplate;
+    public Prototype getPrototype() {
+        return prototype;
     }
 
     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -87,8 +75,8 @@ public class FactTemplateObjectType
      *         object type, else <code>false</code>.
      */
     public boolean matches(final Object object) {
-        if ( object instanceof Fact f ) {
-            return this.factTemplate.equals( f.getFactTemplate() );
+        if ( object instanceof PrototypeFactInstance f ) {
+            return this.prototype.equals( f.getPrototype() );
         } else {
             return false;
         }
@@ -106,16 +94,16 @@ public class FactTemplateObjectType
 
     @Override
     public boolean isAssignableFrom(ObjectType objectType) {
-        if ( !(objectType instanceof FactTemplateObjectType) ) {
+        if ( !(objectType instanceof PrototypeObjectType) ) {
             return false;
         } else {
-            return this.factTemplate.equals( ((FactTemplateObjectType) objectType).getFactTemplate() );
+            return this.prototype.equals( ((PrototypeObjectType) objectType).getPrototype() );
         }
     }
 
     @Override
     public ValueType getValueType() {
-        return ValueType.FACTTEMPLATE_TYPE;
+        return ValueType.PROTOTYPE_TYPE;
     }
 
     @Override
@@ -129,31 +117,31 @@ public class FactTemplateObjectType
 
     @Override
     public Object getTypeKey() {
-        return factTemplate.getName();
+        return prototype.getName();
     }
 
     @Override
-    public boolean isTemplate() {
+    public boolean isPrototype() {
         return true;
     }
 
     @Override
     public String getClassName() {
-        return factTemplate.getPackage() + "." + factTemplate.getName();
+        return prototype.getFullName();
     }
 
     @Override
     public boolean hasField(String name) {
-        return factTemplate.getFieldTemplate(name) != null;
+        return prototype.getField(name) != null;
     }
 
     public Collection<String> getFieldNames() {
-        return factTemplate.getFieldNames();
+        return prototype.getFieldNames();
     }
 
     @Override
     public String toString() {
-        return "[FactTemplateObjectType "+( this.isEvent ? "event=" : "template=") + this.factTemplate.getName() + "]";
+        return "[PrototypeObjectType "+( this.isEvent ? "event=" : "template=") + this.prototype.getName() + "]";
     }
 
     @Override
@@ -162,17 +150,17 @@ public class FactTemplateObjectType
             return true;
         }
 
-        if (!(object instanceof FactTemplateObjectType)) {
+        if (!(object instanceof PrototypeObjectType)) {
             return false;
         }
 
-        final FactTemplateObjectType other = (FactTemplateObjectType) object;
+        final PrototypeObjectType other = (PrototypeObjectType) object;
 
-        return this.factTemplate.equals( other.factTemplate );
+        return this.prototype.equals( other.prototype );
     }
 
     @Override
     public int hashCode() {
-        return this.factTemplate.hashCode();
+        return this.prototype.hashCode();
     }
 }
diff --git a/drools-base/src/main/java/org/drools/base/reteoo/PropertySpecificUtil.java b/drools-base/src/main/java/org/drools/base/reteoo/PropertySpecificUtil.java
index aa634c35c8..dcb45106c1 100644
--- a/drools-base/src/main/java/org/drools/base/reteoo/PropertySpecificUtil.java
+++ b/drools-base/src/main/java/org/drools/base/reteoo/PropertySpecificUtil.java
@@ -26,7 +26,7 @@ import org.drools.base.RuleBase;
 import org.drools.base.base.ClassObjectType;
 import org.drools.base.base.ObjectType;
 import org.drools.base.factmodel.traits.TraitConstants;
-import org.drools.base.facttemplates.FactTemplateObjectType;
+import org.drools.base.prototype.PrototypeObjectType;
 import org.drools.base.rule.TypeDeclaration;
 import org.drools.util.bitmask.AllSetBitMask;
 import org.drools.util.bitmask.AllSetButLastBitMask;
@@ -40,8 +40,8 @@ public class PropertySpecificUtil {
     public static final int CUSTOM_BITS_OFFSET = 1;
 
     public static boolean isPropertyReactive(RuleBase ruleBase, ObjectType objectType) {
-        if (objectType.isTemplate()) {
-            return !((FactTemplateObjectType) objectType).getFieldNames().isEmpty();
+        if (objectType.isPrototype()) {
+            return !((PrototypeObjectType) objectType).getFieldNames().isEmpty();
         }
         TypeDeclaration typeDeclaration = ruleBase.getTypeDeclaration(((ClassObjectType) objectType).getClassType() );
         return typeDeclaration != null && typeDeclaration.isPropertyReactive();
@@ -128,8 +128,8 @@ public class PropertySpecificUtil {
     }
 
     public static List<String> getAccessibleProperties(RuleBase ruleBase, ObjectType objectType) {
-        return objectType.isTemplate() ?
-                new ArrayList<>(((FactTemplateObjectType) objectType).getFieldNames()) :
+        return objectType.isPrototype() ?
+                new ArrayList<>(((PrototypeObjectType) objectType).getFieldNames()) :
                 getAccessibleProperties(ruleBase, ((ClassObjectType) objectType).getClassType());
     }
 
diff --git a/drools-base/src/main/java/org/drools/base/rule/From.java b/drools-base/src/main/java/org/drools/base/rule/From.java
index 37e6371d5c..3a6f8947d6 100644
--- a/drools-base/src/main/java/org/drools/base/rule/From.java
+++ b/drools-base/src/main/java/org/drools/base/rule/From.java
@@ -27,9 +27,9 @@ import java.util.List;
 import java.util.Map;
 
 import org.drools.base.base.ClassObjectType;
-import org.drools.base.facttemplates.Fact;
 import org.drools.base.rule.accessor.DataProvider;
 import org.drools.base.rule.accessor.Wireable;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 public class From extends ConditionalElement
         implements
@@ -131,7 +131,7 @@ public class From extends ConditionalElement
     public Class<?> getResultClass() {
         return resultClass != null ?
                 resultClass :
-                (resultPattern.getObjectType().isTemplate() ? Fact.class : ((ClassObjectType) resultPattern.getObjectType()).getClassType());
+                (resultPattern.getObjectType().isPrototype() ? PrototypeFactInstance.class : ((ClassObjectType) resultPattern.getObjectType()).getClassType());
     }
 
     public void setResultClass(Class<?> resultClass) {
diff --git a/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java b/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
index 78b014161c..f6779f408d 100644
--- a/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
+++ b/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
@@ -29,8 +29,7 @@ import org.drools.base.base.ClassObjectType;
 import org.drools.base.base.ObjectType;
 import org.drools.base.factmodel.ClassDefinition;
 import org.drools.base.factmodel.GeneratedFact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateObjectType;
+import org.drools.base.prototype.PrototypeObjectType;
 import org.drools.base.rule.accessor.ReadAccessor;
 import org.drools.base.util.PropertyReactivityUtil;
 import org.drools.base.util.TimeIntervalParser;
@@ -41,6 +40,7 @@ import org.kie.api.definition.type.Expires.Policy;
 import org.kie.api.definition.type.PropertyReactive;
 import org.kie.api.definition.type.Role;
 import org.kie.api.io.Resource;
+import org.kie.api.prototype.Prototype;
 import org.kie.internal.builder.conf.PropertySpecificOption;
 import org.kie.internal.definition.KnowledgeDefinition;
 
@@ -110,7 +110,7 @@ public class TypeDeclaration
     private ReadAccessor           timestampExtractor;
     private transient Class< ? >   typeClass;
     private String                 typeClassName;
-    private FactTemplate           typeTemplate;
+    private Prototype              prototype;
     private ClassDefinition        typeClassDef;
     private Resource               resource;
     private boolean                dynamic;
@@ -163,7 +163,7 @@ public class TypeDeclaration
 
         this.durationAttribute = null;
         this.timestampAttribute = null;
-        this.typeTemplate = null;
+        this.prototype = null;
         this.typesafe =  true;
         this.valid =  true;
     }
@@ -178,7 +178,7 @@ public class TypeDeclaration
         this.durationAttribute = (String) in.readObject();
         this.timestampAttribute = (String) in.readObject();
         this.typeClassName = (String) in.readObject();
-        this.typeTemplate = (FactTemplate) in.readObject();
+        this.prototype = (Prototype) in.readObject();
         this.typeClassDef = (ClassDefinition) in.readObject();
         this.durationExtractor = (ReadAccessor) in.readObject();
         this.timestampExtractor = (ReadAccessor) in.readObject();
@@ -200,7 +200,7 @@ public class TypeDeclaration
         out.writeObject( durationAttribute );
         out.writeObject( timestampAttribute );
         out.writeObject( typeClassName );
-        out.writeObject( typeTemplate );
+        out.writeObject( prototype );
         out.writeObject( typeClassDef );
         out.writeObject( durationExtractor );
         out.writeObject( timestampExtractor );
@@ -342,26 +342,16 @@ public class TypeDeclaration
         return typeClass != null && GeneratedFact.class.isAssignableFrom( typeClass );
     }
 
-    /**
-     * @return the typeTemplate
-     */
-    public FactTemplate getTypeTemplate() {
-        return typeTemplate;
-    }
-
-    /**
-     * @param typeTemplate the typeTemplate to set
-     */
-    public void setTypeTemplate(FactTemplate typeTemplate) {
-        this.typeTemplate = typeTemplate;
+    public Prototype getPrototype() {
+        return prototype;
     }
 
     /**
      * Returns true if the given parameter matches this type declaration
      */
     public boolean matches(Object clazz) {
-        return clazz instanceof FactTemplate ?
-               this.typeTemplate.equals( clazz ) :
+        return clazz instanceof Prototype ?
+               this.prototype.equals( clazz ) :
                this.typeClass.isAssignableFrom( (Class< ? >) clazz );
     }
 
@@ -444,7 +434,7 @@ public class TypeDeclaration
             if ( this.getFormat() == Format.POJO ) {
                 this.objectType = new ClassObjectType( this.getTypeClass() );
             } else {
-                this.objectType = new FactTemplateObjectType( this.getTypeTemplate() );
+                this.objectType = new PrototypeObjectType(this.getPrototype() );
             }
         }
         return this.objectType;
diff --git a/drools-base/src/main/java/org/drools/base/rule/accessor/GlobalExtractor.java b/drools-base/src/main/java/org/drools/base/rule/accessor/GlobalExtractor.java
index fb4808e5fd..5988701cfc 100755
--- a/drools-base/src/main/java/org/drools/base/rule/accessor/GlobalExtractor.java
+++ b/drools-base/src/main/java/org/drools/base/rule/accessor/GlobalExtractor.java
@@ -29,8 +29,8 @@ import org.drools.base.base.ClassObjectType;
 import org.drools.base.base.ObjectType;
 import org.drools.base.base.ValueResolver;
 import org.drools.base.base.extractors.BaseObjectClassFieldReader;
-import org.drools.base.facttemplates.Fact;
 import org.drools.util.ClassUtils;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 /**
  * This is a global variable extractor used to get a global variable value
@@ -91,7 +91,7 @@ public class GlobalExtractor extends BaseObjectClassFieldReader
         if ( this.objectType instanceof ClassObjectType cot ) {
             return cot.getClassType();
         } else {
-            return Fact.class;
+            return PrototypeFactInstance.class;
         }
     }
 
@@ -101,7 +101,7 @@ public class GlobalExtractor extends BaseObjectClassFieldReader
         if ( this.objectType instanceof ClassObjectType cot ) {
             clazz = cot.getClassType();
         } else {
-            clazz = Fact.class;
+            clazz = PrototypeFactInstance.class;
         }
         return ClassUtils.canonicalName( clazz );
     }
diff --git a/drools-base/src/main/java/org/drools/base/rule/accessor/PatternExtractor.java b/drools-base/src/main/java/org/drools/base/rule/accessor/PatternExtractor.java
index 5981010738..d5e274eb90 100644
--- a/drools-base/src/main/java/org/drools/base/rule/accessor/PatternExtractor.java
+++ b/drools-base/src/main/java/org/drools/base/rule/accessor/PatternExtractor.java
@@ -29,8 +29,8 @@ import org.drools.base.base.ClassObjectType;
 import org.drools.base.base.ObjectType;
 import org.drools.base.base.ValueResolver;
 import org.drools.base.base.extractors.BaseObjectClassFieldReader;
-import org.drools.base.facttemplates.Fact;
 import org.drools.util.ClassUtils;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 public class PatternExtractor extends BaseObjectClassFieldReader
     implements
@@ -85,14 +85,14 @@ public class PatternExtractor extends BaseObjectClassFieldReader
         if ( this.objectType instanceof ClassObjectType ) {
             return ((ClassObjectType) this.objectType).getClassType();
         } else {
-            return Fact.class;
+            return PrototypeFactInstance.class;
         }
     }
 
     public String getExtractToClassName() {
         Class<?> clazz = this.objectType instanceof ClassObjectType ?
                          ((ClassObjectType) this.objectType).getClassType() :
-                         Fact.class;
+                         PrototypeFactInstance.class;
         return ClassUtils.canonicalName( clazz );
     }
 
diff --git a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/DroolsAssemblerContextImpl.java b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/DroolsAssemblerContextImpl.java
index 74e0c96e6d..8478e263a0 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/DroolsAssemblerContextImpl.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/DroolsAssemblerContextImpl.java
@@ -92,7 +92,7 @@ public class DroolsAssemblerContextImpl implements DroolsAssemblerContext, Build
 
     @Override
     public TypeDeclaration getTypeDeclaration(ObjectType objectType) {
-        return objectType.isTemplate() ?
+        return objectType.isPrototype() ?
                 typeBuilder.getExistingTypeDeclaration(objectType.getClassName()) :
                 typeBuilder.getTypeDeclaration(((ClassObjectType) objectType).getClassType());
     }
diff --git a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/KnowledgeBuilderRulesConfigurationImpl.java b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/KnowledgeBuilderRulesConfigurationImpl.java
index e34574cd3b..09ee9e930f 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/KnowledgeBuilderRulesConfigurationImpl.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/KnowledgeBuilderRulesConfigurationImpl.java
@@ -31,6 +31,7 @@ import org.drools.core.BaseConfiguration;
 import org.drools.drl.parser.DrlParser;
 import org.kie.api.conf.ConfigurationKey;
 import org.kie.api.conf.OptionKey;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.runtime.rule.AccumulateFunction;
 import org.kie.internal.builder.KnowledgeBuilderConfiguration;
 import org.kie.internal.builder.conf.AccumulateFunctionOption;
@@ -106,6 +107,8 @@ public class KnowledgeBuilderRulesConfigurationImpl extends BaseConfiguration<Kn
     private static final PropertySpecificOption DEFAULT_PROP_SPEC_OPT = PropertySpecificOption.ALWAYS;
     private PropertySpecificOption            propertySpecificOption  = DEFAULT_PROP_SPEC_OPT;
 
+    private PrototypesOption                  prototypesOption  = PrototypesOption.DISABLED;
+
     private LanguageLevelOption               languageLevel           = DrlParser.DEFAULT_LANGUAGE_LEVEL;
 
     private CompilationCache                  compilationCache        = null;
@@ -165,9 +168,12 @@ public class KnowledgeBuilderRulesConfigurationImpl extends BaseConfiguration<Kn
         return getClassLoader();
     }
 
-    public boolean setInternalProperty(String name,
-                                       String value) {
+    public boolean setInternalProperty(String name, String value) {
         switch (name) {
+            case PrototypesOption.PROPERTY_NAME: {
+                setPrototypesOption(PrototypesOption.determinePrototypesOption(value));
+                break;
+            }
             case ProcessStringEscapesOption.PROPERTY_NAME: {
                 setProcessStringEscapes(Boolean.parseBoolean(value));
                 break;
@@ -382,6 +388,14 @@ public class KnowledgeBuilderRulesConfigurationImpl extends BaseConfiguration<Kn
         this.propertySpecificOption = propertySpecificOption;
     }
 
+    public PrototypesOption getPrototypesOption() {
+        return prototypesOption;
+    }
+
+    public void setPrototypesOption(PrototypesOption prototypesOption) {
+        this.prototypesOption = prototypesOption;
+    }
+
     public boolean isExternaliseCanonicalModelLambda() {
         return externaliseCanonicalModelLambda;
     }
diff --git a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationManagerImpl.java b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationManagerImpl.java
index 2c847740b8..11ddb625c3 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationManagerImpl.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationManagerImpl.java
@@ -64,7 +64,7 @@ public class TypeDeclarationManagerImpl implements TypeDeclarationManager {
 
     @Override
     public TypeDeclaration getTypeDeclaration(ObjectType objectType) {
-        return objectType.isTemplate() ?
+        return objectType.isPrototype() ?
                 typeBuilder.getExistingTypeDeclaration(objectType.getClassName()) :
                 typeBuilder.getTypeDeclaration(((ClassObjectType) objectType).getClassType());
     }
diff --git a/drools-compiler/src/main/java/org/drools/compiler/compiler/BoundIdentifiers.java b/drools-compiler/src/main/java/org/drools/compiler/compiler/BoundIdentifiers.java
index a4e6207973..4ad5d5027e 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/compiler/BoundIdentifiers.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/compiler/BoundIdentifiers.java
@@ -26,13 +26,13 @@ import java.util.Map;
 
 import org.drools.base.base.ClassObjectType;
 import org.drools.base.base.ObjectType;
-import org.drools.base.facttemplates.Fact;
 import org.drools.base.rule.Declaration;
 import org.drools.base.rule.Pattern;
 import org.drools.base.rule.XpathBackReference;
 import org.drools.compiler.rule.builder.EvaluatorWrapper;
 import org.drools.compiler.rule.builder.PackageBuildContext;
 import org.drools.compiler.rule.builder.RuleBuildContext;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 import static org.drools.util.ClassUtils.rawType;
 
@@ -62,7 +62,7 @@ public class BoundIdentifiers {
                             PackageBuildContext context,
                             Map<String, EvaluatorWrapper> operators,
                             ObjectType objectType) {
-        this(getDeclarationsMap( pattern, context ), context, operators, objectType.isTemplate() ? Fact.class : ((ClassObjectType) objectType).getClassType());
+        this(getDeclarationsMap( pattern, context ), context, operators, objectType.isPrototype() ? PrototypeFactInstance.class : ((ClassObjectType) objectType).getClassType());
     }
 
     public BoundIdentifiers(Map<String, Class< ? >> declarations,
diff --git a/drools-compiler/src/main/java/org/drools/compiler/compiler/FactTemplateError.java b/drools-compiler/src/main/java/org/drools/compiler/compiler/FactTemplateError.java
deleted file mode 100644
index 33996d979a..0000000000
--- a/drools-compiler/src/main/java/org/drools/compiler/compiler/FactTemplateError.java
+++ /dev/null
@@ -1,73 +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.drools.compiler.compiler;
-
-import org.drools.drl.ast.descr.BaseDescr;
-import org.drools.drl.parser.DroolsError;
-
-public class FactTemplateError extends DroolsError {
-    private Package   pkg;
-    private BaseDescr descr;
-    private Object    object;
-    private int[]     line;
-    private String    namespace;
-
-    public FactTemplateError(final Package pkg,
-                             final BaseDescr descr,
-                             final Object object,
-                             final String message) {
-        super(descr.getResource(), BuilderResultUtils.getProblemMessage( object, message ));
-        this.namespace = pkg.getName();
-        this.pkg = pkg;
-        this.descr = descr;
-        this.object = object;
-        this.line = new int[] {this.descr.getLine()};
-    }
-
-    @Override
-    public String getNamespace() {
-        return namespace;
-    }
-
-    public Package getPackage() {
-        return this.pkg;
-    }
-
-    public BaseDescr getDescr() {
-        return this.descr;
-    }
-
-    public Object getObject() {
-        return this.object;
-    }
-    
-    public int[] getLines() {
-        return this.line;
-    }
-
-    /** 
-     * This will return the line number of the error, if possible
-     * Otherwise it will be -1
-     */
-    public int getLine() {
-        return this.line[0];
-    }
-
-
-}
diff --git a/drools-compiler/src/main/java/org/drools/compiler/compiler/FieldTemplateError.java b/drools-compiler/src/main/java/org/drools/compiler/compiler/FieldTemplateError.java
deleted file mode 100644
index 30d746f126..0000000000
--- a/drools-compiler/src/main/java/org/drools/compiler/compiler/FieldTemplateError.java
+++ /dev/null
@@ -1,72 +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.drools.compiler.compiler;
-
-import org.drools.drl.ast.descr.BaseDescr;
-import org.drools.drl.parser.DroolsError;
-
-public class FieldTemplateError extends DroolsError {
-    private Package   pkg;
-    private BaseDescr descr;
-    private Object    object;
-    private int[]     line;
-    private String    namespace;
-
-    public FieldTemplateError(final Package pkg,
-                              final BaseDescr descr,
-                              final Object object,
-                              final String message) {
-        super(descr.getResource(), BuilderResultUtils.getProblemMessage( object, message ));
-        this.namespace = pkg.getName();
-        this.pkg = pkg;
-        this.descr = descr;
-        this.object = object;
-        this.line = new int[] {this.descr.getLine()};
-    }
-
-    @Override
-    public String getNamespace() {
-        return namespace;
-    }
-
-    public Package getPackage() {
-        return this.pkg;
-    }
-
-    public BaseDescr getDescr() {
-        return this.descr;
-    }
-
-    public Object getObject() {
-        return this.object;
-    }
-    
-    public int[] getLines() {
-        return this.line;
-    }
-
-    /** 
-     * This will return the line number of the error, if possible
-     * Otherwise it will be -1
-     */
-    public int getLine() {
-        return this.line[0];
-    }
-
-}
diff --git a/drools-compiler/src/main/java/org/drools/compiler/kie/builder/impl/AbstractKieModule.java b/drools-compiler/src/main/java/org/drools/compiler/kie/builder/impl/AbstractKieModule.java
index 16e8186af6..de8b1839cb 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/kie/builder/impl/AbstractKieModule.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/kie/builder/impl/AbstractKieModule.java
@@ -32,6 +32,7 @@ import java.util.Properties;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+import org.drools.base.RuleBase;
 import org.drools.base.definitions.InternalKnowledgePackage;
 import org.drools.base.definitions.impl.KnowledgePackageImpl;
 import org.drools.compiler.builder.InternalKnowledgeBuilder;
@@ -39,8 +40,6 @@ import org.drools.compiler.builder.conf.DecisionTableConfigurationImpl;
 import org.drools.compiler.builder.impl.KnowledgeBuilderConfigurationImpl;
 import org.drools.compiler.kproject.models.KieBaseModelImpl;
 import org.drools.core.RuleBaseConfiguration;
-import org.drools.base.definitions.InternalKnowledgePackage;
-import org.drools.base.definitions.impl.KnowledgePackageImpl;
 import org.drools.core.impl.RuleBaseFactory;
 import org.drools.io.ResourceConfigurationImpl;
 import org.drools.kiesession.rulebase.InternalKnowledgeBase;
@@ -54,6 +53,7 @@ import org.kie.api.builder.model.KieBaseModel;
 import org.kie.api.builder.model.KieModuleModel;
 import org.kie.api.builder.model.RuleTemplateModel;
 import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.definition.KiePackage;
 import org.kie.api.io.Resource;
 import org.kie.api.io.ResourceConfiguration;
@@ -70,7 +70,6 @@ import org.kie.util.maven.support.PomModel;
 import org.kie.util.maven.support.ReleaseIdImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.drools.base.RuleBase;
 
 import static org.kie.internal.builder.KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration;
 
@@ -252,11 +251,15 @@ public abstract class AbstractKieModule implements InternalKieModule, Serializab
     public KnowledgeBuilderConfiguration createBuilderConfiguration( KieBaseModel kBaseModel, ClassLoader classLoader) {
         KnowledgeBuilderConfigurationImpl pconf = newKnowledgeBuilderConfiguration(classLoader).as(KnowledgeBuilderConfigurationImpl.KEY);
         pconf.setCompilationCache(getCompilationCache(kBaseModel.getName()));
-        setModelPropsOnConf( ((KieBaseModelImpl) kBaseModel).getKModule(), pconf );
+        setModelPropsOnConf( kBaseModel, pconf );
         return pconf;
     }
 
-    static void setModelPropsOnConf( KieModuleModel kModuleModel, KnowledgeBuilderConfigurationImpl pconf ) {
+    private static void setModelPropsOnConf( KieBaseModel kBaseModel, KnowledgeBuilderConfigurationImpl pconf ) {
+        if (kBaseModel.getPrototypes() != null) {
+            pconf.setProperty(PrototypesOption.PROPERTY_NAME, kBaseModel.getPrototypes().toString());
+        }
+        KieModuleModel kModuleModel = ((KieBaseModelImpl) kBaseModel).getKModule();
         for (Map.Entry<String, String> entry : kModuleModel.getConfigurationProperties().entrySet()) {
             pconf.setProperty(entry.getKey(), entry.getValue());
         }
diff --git a/drools-compiler/src/main/java/org/drools/compiler/kproject/models/KieBaseModelImpl.java b/drools-compiler/src/main/java/org/drools/compiler/kproject/models/KieBaseModelImpl.java
index c4c1361de0..ff42cd4d16 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/kproject/models/KieBaseModelImpl.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/kproject/models/KieBaseModelImpl.java
@@ -39,6 +39,7 @@ import org.kie.api.conf.DeclarativeAgendaOption;
 import org.kie.api.conf.EqualityBehaviorOption;
 import org.kie.api.conf.EventProcessingOption;
 import org.kie.api.conf.KieBaseMutabilityOption;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.conf.SequentialOption;
 import org.kie.api.conf.SessionsPoolOption;
 import org.kie.api.io.ResourceType;
@@ -57,6 +58,8 @@ public class KieBaseModelImpl
 
     private EqualityBehaviorOption       equalsBehavior = EqualityBehaviorOption.IDENTITY;
 
+    private PrototypesOption             prototypes = PrototypesOption.DISABLED;
+
     private KieBaseMutabilityOption      mutability = KieBaseMutabilityOption.ALLOWED;
 
     private EventProcessingOption        eventProcessingMode = EventProcessingOption.CLOUD;
@@ -234,21 +237,24 @@ public class KieBaseModelImpl
         return this;
     }
 
-    /* (non-Javadoc)
-     * @see org.kie.kproject.KieBaseModel#getEqualsBehavior()
-     */
     public EqualityBehaviorOption getEqualsBehavior() {
         return equalsBehavior;
     }
 
-    /* (non-Javadoc)
-     * @see org.kie.kproject.KieBaseModel#setEqualsBehavior(org.kie.api.conf.EqualityBehaviorOption)
-     */
     public KieBaseModel setEqualsBehavior(EqualityBehaviorOption equalsBehaviour) {
         this.equalsBehavior = equalsBehaviour;
         return this;
     }
 
+    public PrototypesOption getPrototypes() {
+        return prototypes;
+    }
+
+    public KieBaseModel setPrototypes(PrototypesOption prototypes) {
+        this.prototypes = prototypes;
+        return this;
+    }
+
     public KieBaseMutabilityOption getMutability() {
         return mutability;
     }
@@ -353,7 +359,7 @@ public class KieBaseModelImpl
 
     @Override
     public String toString() {
-        return "KieBaseModelImpl [name=" + name + ", includes=" + includes + ", packages=" + getPackages() + ", equalsBehavior=" + equalsBehavior + ", mutability=" + mutability + ", eventProcessingMode=" + eventProcessingMode + ", kSessions=" + kSessions + "]";
+        return "KieBaseModelImpl [name=" + name + ", includes=" + includes + ", packages=" + getPackages() + ", equalsBehavior=" + equalsBehavior + ", prototypes=" + prototypes + ", mutability=" + mutability + ", eventProcessingMode=" + eventProcessingMode + ", kSessions=" + kSessions + "]";
     }
 
     @Override
diff --git a/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java b/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java
index d50ef6c1bc..fdd709abcd 100644
--- a/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java
+++ b/drools-compiler/src/main/java/org/drools/compiler/rule/builder/PatternBuilder.java
@@ -42,9 +42,8 @@ import org.drools.base.definitions.rule.impl.RuleImpl;
 import org.drools.base.factmodel.AnnotationDefinition;
 import org.drools.base.factmodel.ClassDefinition;
 import org.drools.base.factmodel.FieldDefinition;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateFieldExtractor;
-import org.drools.base.facttemplates.FactTemplateObjectType;
+import org.drools.base.prototype.PrototypeFieldExtractor;
+import org.drools.base.prototype.PrototypeObjectType;
 import org.drools.base.reteoo.SortDeclarations;
 import org.drools.base.rule.Declaration;
 import org.drools.base.rule.Pattern;
@@ -105,6 +104,7 @@ import org.drools.util.StringUtils;
 import org.drools.util.TypeResolver;
 import org.kie.api.definition.rule.Watch;
 import org.kie.api.definition.type.Role;
+import org.kie.api.prototype.Prototype;
 import org.kie.internal.builder.KnowledgeBuilderResult;
 import org.kie.internal.builder.ResultSeverity;
 import org.kie.internal.builder.conf.LanguageLevelOption;
@@ -321,9 +321,9 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
     }
 
     private ObjectType getObjectType(RuleBuildContext context, PatternDescr patternDescr, String objectType) {
-        final FactTemplate factTemplate = context.getPkg().getFactTemplate(objectType);
-        if (factTemplate != null) {
-            return new FactTemplateObjectType(factTemplate);
+        Prototype prototype = context.getPkg().getPrototype(objectType);
+        if (prototype != null) {
+            return new PrototypeObjectType(prototype);
         } else {
             try {
                 final Class<?> userProvidedClass = context.getDialect().getTypeResolver().resolveType(objectType);
@@ -558,8 +558,8 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
 
     protected Collection<String> getSettableProperties(RuleBuildContext context, PatternDescr patternDescr, Pattern pattern) {
         ObjectType patternType = pattern.getObjectType();
-        if (patternType.isTemplate()) {
-            return ((FactTemplateObjectType) patternType).getFieldNames();
+        if (patternType.isPrototype()) {
+            return ((PrototypeObjectType) patternType).getFieldNames();
         }
 
         Class<?> patternClass = ((ClassObjectType) patternType).getClassType();
@@ -843,7 +843,7 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
         XpathConstraint xpathConstraint = new XpathConstraint();
         ObjectType objectType = pattern.getObjectType();
 
-        if (objectType.isTemplate()) {
+        if (objectType.isPrototype()) {
             throw new UnsupportedOperationException("xpath is not supported with fact templates");
         }
 
@@ -1086,8 +1086,8 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
         }
 
         ObjectType objectType = pattern.getObjectType();
-        if (objectType.isTemplate()) {
-            return ((FactTemplateObjectType) objectType).getFactTemplate().getFieldTemplate(leftValue).getValueType();
+        if (objectType.isPrototype()) {
+            return ValueType.determineValueType( ( (PrototypeObjectType) objectType).getPrototype().getField(leftValue).getType() );
         }
 
         Class<?> clazz = ((ClassObjectType) objectType).getClassType();
@@ -1121,7 +1121,7 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
         ConstraintBuilder.get().setExprInputs( context, valueExpr,
                                                (pattern.getObjectType() instanceof ClassObjectType) ?
                                                        ((ClassObjectType) pattern.getObjectType()).getClassType() :
-                                                       FactTemplate.class,
+                                                       Prototype.class,
                                                value);
         if (!isIdentifierLiteral(value)) {
             String identifier = StringUtils.extractFirstIdentifier(value, 0);
@@ -1533,7 +1533,7 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
             mvelDeclarations[i++] = context.getDeclarationResolver().getDeclaration(global);
         }
 
-        boolean isDynamic = pattern.getObjectType().isTemplate() ||
+        boolean isDynamic = pattern.getObjectType().isPrototype() ||
                 ( !((ClassObjectType) pattern.getObjectType()).getClassType().isArray() &&
                         !context.getKnowledgeBuilder().getTypeDeclaration(pattern.getObjectType()).isTypesafe() );
 
@@ -1721,7 +1721,7 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
                                             final ObjectType objectType,
                                             final String fieldName,
                                             final AcceptsReadAccessor target) {
-        if (!ValueType.FACTTEMPLATE_TYPE.equals(objectType.getValueType())) {
+        if (!ValueType.PROTOTYPE_TYPE.equals(objectType.getValueType())) {
             context.getPkg().getReader(objectType.getClassName(), fieldName, target);
         }
     }
@@ -1745,10 +1745,9 @@ public class PatternBuilder implements RuleConditionBuilder<PatternDescr> {
         // reportError is needed as some times failure to build accessor is not a failure, just an indication that building is not possible so try something else.
         ReadAccessor reader;
 
-        if (ValueType.FACTTEMPLATE_TYPE.equals(objectType.getValueType())) {
+        if (ValueType.PROTOTYPE_TYPE.equals(objectType.getValueType())) {
             //@todo use accessor cache            
-            final FactTemplate factTemplate = ((FactTemplateObjectType) objectType).getFactTemplate();
-            reader = new FactTemplateFieldExtractor(factTemplate, fieldName);
+            reader = new PrototypeFieldExtractor(((PrototypeObjectType) objectType).getPrototype(), fieldName);
             if (target != null) {
                 target.setReadAccessor(reader);
             }
diff --git a/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java b/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java
index 214e8ea8ce..d9be2283d0 100755
--- a/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java
+++ b/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java
@@ -37,6 +37,7 @@ import org.kie.api.conf.EventProcessingOption;
 import org.kie.api.conf.KieBaseOption;
 import org.kie.api.conf.MultiValueKieBaseOption;
 import org.kie.api.conf.OptionKey;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.conf.RemoveIdentitiesOption;
 import org.kie.api.conf.SequentialOption;
 import org.kie.api.conf.SessionsPoolOption;
@@ -141,6 +142,8 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
 
     private EventProcessingOption eventProcessingMode;
 
+    private PrototypesOption prototypesOption;
+
     private IndexPrecedenceOption indexPrecedenceOption;
 
     // if parallelism is enabled, rulebase builder will try to split
@@ -202,17 +205,15 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
 
         setSequential(Boolean.parseBoolean(getPropertyValue(SequentialOption.PROPERTY_NAME, "false")));
 
-        setParallelExecution(ParallelExecutionOption.determineParallelExecution(getPropertyValue(ParallelExecutionOption.PROPERTY_NAME,
-                "sequential")));
+        setParallelExecution(ParallelExecutionOption.determineParallelExecution(getPropertyValue(ParallelExecutionOption.PROPERTY_NAME, "sequential")));
+
+        setMaxThreads( Integer.parseInt( getPropertyValue( MaxThreadsOption.PROPERTY_NAME, "3" ) ) );
 
-        setMaxThreads( Integer.parseInt( getPropertyValue( MaxThreadsOption.PROPERTY_NAME,
-                                                                             "3" ) ) );
+        setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( getPropertyValue( EventProcessingOption.PROPERTY_NAME, "cloud" ) ) );
 
-        setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( getPropertyValue( EventProcessingOption.PROPERTY_NAME,
-                                                                                                                        "cloud" ) ) );
+        setPrototypesOption( PrototypesOption.determinePrototypesOption( getPropertyValue( PrototypesOption.PROPERTY_NAME, "disabled" ) ) );
 
-        setDeclarativeAgendaEnabled( Boolean.parseBoolean(getPropertyValue(DeclarativeAgendaOption.PROPERTY_NAME,
-                                                                                             "false")) );
+        setDeclarativeAgendaEnabled( Boolean.parseBoolean(getPropertyValue(DeclarativeAgendaOption.PROPERTY_NAME, "false")) );
     }
 
     public void writeExternal(ObjectOutput out) throws IOException {
@@ -333,6 +334,9 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
             case EventProcessingOption.PROPERTY_NAME: {
                 return (T) getEventProcessingMode();
             }
+            case PrototypesOption.PROPERTY_NAME: {
+                return (T) getPrototypesOption();
+            }
             case MaxThreadsOption.PROPERTY_NAME: {
                 return (T) MaxThreadsOption.get(getMaxThreads());
             }
@@ -417,6 +421,10 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
                 setEventProcessingMode( (EventProcessingOption) option);
                 break;
             }
+            case PrototypesOption.PROPERTY_NAME: {
+                setPrototypesOption( (PrototypesOption) option);
+                break;
+            }
             case MaxThreadsOption.PROPERTY_NAME: {
                 setMaxThreads( ( (MaxThreadsOption) option ).getMaxThreads());
                 break;
@@ -516,6 +524,10 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
                 setEventProcessingMode(EventProcessingOption.determineEventProcessingMode(StringUtils.isEmpty(value) ? "cloud" : value));
                 break;
             }
+            case PrototypesOption.PROPERTY_NAME: {
+                setPrototypesOption(PrototypesOption.determinePrototypesOption(StringUtils.isEmpty(value) ? "disabled" : value));
+                break;
+            }
             default : {
                 return false;
             }
@@ -586,6 +598,9 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
             case EventProcessingOption.PROPERTY_NAME: {
                 return getEventProcessingMode().getMode();
             }
+            case PrototypesOption.PROPERTY_NAME: {
+                return getPrototypesOption().toString().toLowerCase();
+            }
         }
 
         return null;
@@ -698,6 +713,15 @@ public class RuleBaseConfiguration  extends BaseConfiguration<KieBaseOption, Sin
         this.eventProcessingMode = mode;
     }
 
+    public PrototypesOption getPrototypesOption() {
+        return this.prototypesOption;
+    }
+
+    public void setPrototypesOption(final PrototypesOption prototypesOption) {
+        checkCanChange(); // throws an exception if a change isn't possible;
+        this.prototypesOption = prototypesOption;
+    }
+
     public int getCompositeKeyDepth() {
         return this.compositeKeyDepth;
     }
diff --git a/drools-core/src/main/java/org/drools/core/common/ObjectTypeConfigurationRegistry.java b/drools-core/src/main/java/org/drools/core/common/ObjectTypeConfigurationRegistry.java
index 8821488803..aab549640e 100644
--- a/drools-core/src/main/java/org/drools/core/common/ObjectTypeConfigurationRegistry.java
+++ b/drools-core/src/main/java/org/drools/core/common/ObjectTypeConfigurationRegistry.java
@@ -25,15 +25,14 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import org.drools.base.base.ClassObjectType;
 import org.drools.base.base.ObjectType;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactImpl;
 import org.drools.base.rule.EntryPointId;
 import org.drools.core.impl.InternalRuleBase;
 import org.drools.core.reteoo.ClassObjectTypeConf;
-import org.drools.core.reteoo.FactTemplateTypeConf;
 import org.drools.core.reteoo.ObjectTypeConf;
+import org.drools.core.reteoo.PrototypeTypeConf;
 import org.drools.core.reteoo.RuleTerminalNodeLeftTuple;
 import org.drools.core.rule.consequence.InternalMatch;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 public class ObjectTypeConfigurationRegistry implements Serializable {
     private static final long serialVersionUID = 510l;
@@ -73,10 +72,8 @@ public class ObjectTypeConfigurationRegistry implements Serializable {
     private Object getKey( Object object ) {
         if (object instanceof RuleTerminalNodeLeftTuple) {
             return ClassObjectType.Match_ObjectType.getClassType();
-        } else if (object instanceof FactImpl) {
-            return ((FactImpl) object).getFactTemplate().getName();
-        } else if (object instanceof Fact) {
-            return ((Fact) object).getFactTemplate().getName();
+        } else if (object instanceof PrototypeFactInstance p) {
+            return p.getPrototype().getFullName();
         } else if (object instanceof InternalMatch) {
             return ClassObjectType.Match_ObjectType.getClassType();
         }
@@ -84,8 +81,8 @@ public class ObjectTypeConfigurationRegistry implements Serializable {
     }
 
     private ObjectTypeConf createObjectTypeConf(EntryPointId entrypoint, Object key, Object object) {
-        return object instanceof Fact ?
-                new FactTemplateTypeConf( entrypoint, ((Fact) object).getFactTemplate(), this.ruleBase ) :
+        return object instanceof PrototypeFactInstance p ?
+                new PrototypeTypeConf(entrypoint, p.getPrototype(), this.ruleBase ) :
                 new ClassObjectTypeConf( entrypoint, (Class<?>) key, this.ruleBase );
     }
 
diff --git a/drools-core/src/main/java/org/drools/core/phreak/PropagationEntry.java b/drools-core/src/main/java/org/drools/core/phreak/PropagationEntry.java
index d2163e62fd..a3c02ff349 100644
--- a/drools-core/src/main/java/org/drools/core/phreak/PropagationEntry.java
+++ b/drools-core/src/main/java/org/drools/core/phreak/PropagationEntry.java
@@ -24,7 +24,6 @@ import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.util.concurrent.CountDownLatch;
 
-import org.drools.base.facttemplates.Event;
 import org.drools.base.reteoo.NodeTypeEnums;
 import org.drools.core.base.DroolsQueryImpl;
 import org.drools.core.common.DefaultEventHandle;
@@ -46,6 +45,7 @@ import org.drools.core.reteoo.TerminalNode;
 import org.drools.core.time.JobContext;
 import org.drools.core.time.impl.DefaultJobHandle;
 import org.drools.core.time.impl.PointInTimeTrigger;
+import org.kie.api.prototype.PrototypeEventInstance;
 
 import static org.drools.base.rule.TypeDeclaration.NEVER_EXPIRES;
 import static org.drools.core.reteoo.EntryPointNode.removeRightTuplesMatchingOTN;
@@ -252,11 +252,11 @@ public interface PropagationEntry {
 
         private static void scheduleExpiration(ReteEvaluator reteEvaluator, InternalFactHandle handle, PropagationContext context, ObjectTypeConf objectTypeConf, long insertionTime) {
             for ( ObjectTypeNode otn : objectTypeConf.getObjectTypeNodes() ) {
-                long expirationOffset = objectTypeConf.isPrototype() ? ((Event) handle.getObject()).getExpiration() : otn.getExpirationOffset();
+                long expirationOffset = objectTypeConf.isPrototype() ? ((PrototypeEventInstance) handle.getObject()).getExpiration() : otn.getExpirationOffset();
                 scheduleExpiration( reteEvaluator, handle, context, otn, insertionTime, expirationOffset );
             }
             if ( objectTypeConf.getConcreteObjectTypeNode() == null ) {
-                long expirationOffset = objectTypeConf.isPrototype() ? ((Event) handle.getObject()).getExpiration() : ((ClassObjectTypeConf) objectTypeConf).getExpirationOffset();
+                long expirationOffset = objectTypeConf.isPrototype() ? ((PrototypeEventInstance) handle.getObject()).getExpiration() : ((ClassObjectTypeConf) objectTypeConf).getExpirationOffset();
                 scheduleExpiration( reteEvaluator, handle, context, null, insertionTime, expirationOffset);
             }
         }
diff --git a/drools-core/src/main/java/org/drools/core/reteoo/FactTemplateTypeConf.java b/drools-core/src/main/java/org/drools/core/reteoo/PrototypeTypeConf.java
similarity index 80%
rename from drools-core/src/main/java/org/drools/core/reteoo/FactTemplateTypeConf.java
rename to drools-core/src/main/java/org/drools/core/reteoo/PrototypeTypeConf.java
index 7ac53a3b21..d8d3f96584 100644
--- a/drools-core/src/main/java/org/drools/core/reteoo/FactTemplateTypeConf.java
+++ b/drools-core/src/main/java/org/drools/core/reteoo/PrototypeTypeConf.java
@@ -24,10 +24,7 @@ import java.io.ObjectInput;
 import java.io.ObjectOutput;
 
 import org.drools.base.base.ObjectType;
-import org.drools.base.facttemplates.Event;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateObjectType;
+import org.drools.base.prototype.PrototypeObjectType;
 import org.drools.base.rule.EntryPointId;
 import org.drools.base.rule.TypeDeclaration;
 import org.drools.core.WorkingMemoryEntryPoint;
@@ -35,8 +32,11 @@ import org.drools.core.common.InternalFactHandle;
 import org.drools.core.common.ReteEvaluator;
 import org.drools.core.impl.InternalRuleBase;
 import org.drools.core.rule.accessor.FactHandleFactory;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeEventInstance;
+import org.kie.api.prototype.PrototypeFactInstance;
 
-public class FactTemplateTypeConf
+public class PrototypeTypeConf
     implements
     ObjectTypeConf,
     Externalizable {
@@ -45,33 +45,33 @@ public class FactTemplateTypeConf
 
     private transient InternalRuleBase ruleBase;
 
-    private ObjectType        objectType;
-    private FactTemplate      factTemplate;
-    private ObjectTypeNode    concreteObjectTypeNode;
-    private ObjectTypeNode[]  cache;
+    private ObjectType objectType;
+    private Prototype prototype;
+    private ObjectTypeNode concreteObjectTypeNode;
+    private ObjectTypeNode[] cache;
     
-    private boolean          tmsEnabled;
+    private boolean tmsEnabled;
     
     EntryPointId entryPoint;
 
 
-    public FactTemplateTypeConf() {
+    public PrototypeTypeConf() {
     }
 
-    public FactTemplateTypeConf(final EntryPointId entryPoint,
-                                final FactTemplate factTemplate,
-                                final InternalRuleBase ruleBase) {
+    public PrototypeTypeConf(final EntryPointId entryPoint,
+                             final Prototype prototype,
+                             final InternalRuleBase ruleBase) {
         this.ruleBase = ruleBase;
-        this.factTemplate = factTemplate;
+        this.prototype = prototype;
         this.entryPoint = entryPoint;
-        this.objectType = new FactTemplateObjectType( factTemplate );
+        this.objectType = new PrototypeObjectType(prototype);
         this.concreteObjectTypeNode = ruleBase.getRete().getObjectTypeNodes( entryPoint ).get( objectType );
     }
 
     public void readExternal(ObjectInput in) throws IOException,
                                             ClassNotFoundException {
         ruleBase = (InternalRuleBase) in.readObject();
-        factTemplate = (FactTemplate) in.readObject();
+        prototype = (Prototype) in.readObject();
         concreteObjectTypeNode = (ObjectTypeNode) in.readObject();
         cache = (ObjectTypeNode[]) in.readObject();
         objectType = (ObjectType) in.readObject();
@@ -79,7 +79,7 @@ public class FactTemplateTypeConf
 
     public void writeExternal(ObjectOutput out) throws IOException {
         out.writeObject( ruleBase );
-        out.writeObject( factTemplate );
+        out.writeObject( prototype );
         out.writeObject( concreteObjectTypeNode );
         out.writeObject( cache );
         out.writeObject( objectType );
@@ -100,7 +100,7 @@ public class FactTemplateTypeConf
     }
 
     public boolean isAssignableFrom(Object object) {
-        return this.factTemplate.equals( object );
+        return this.prototype.equals( object );
     }
 
     public void resetCache() {
@@ -145,15 +145,15 @@ public class FactTemplateTypeConf
 
     @Override
     public String getTypeName() {
-        return factTemplate.getName();
+        return prototype.getFullName();
     }
 
     @Override
     public InternalFactHandle createFactHandle(FactHandleFactory factHandleFactory, long id, Object object, long recency,
                                                ReteEvaluator reteEvaluator, WorkingMemoryEntryPoint entryPoint) {
-        Fact fact = (Fact) object;
+        PrototypeFactInstance fact = (PrototypeFactInstance) object;
         if (fact.isEvent()) {
-            Event event = (Event) fact;
+            PrototypeEventInstance event = (PrototypeEventInstance) fact;
             long timestamp = event.getTimestamp() >= 0 ? event.getTimestamp() : reteEvaluator.getTimerService().getCurrentTime();
             return factHandleFactory.createEventFactHandle(id, object, recency, entryPoint, timestamp, 0);
         }
diff --git a/drools-core/src/test/java/org/drools/core/facttemplates/FactTemplateFieldExtractorTest.java b/drools-core/src/test/java/org/drools/core/facttemplates/FactTemplateFieldExtractorTest.java
deleted file mode 100644
index ec769f2427..0000000000
--- a/drools-core/src/test/java/org/drools/core/facttemplates/FactTemplateFieldExtractorTest.java
+++ /dev/null
@@ -1,108 +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.drools.core.facttemplates;
-
-import org.drools.base.definitions.InternalKnowledgePackage;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateFieldExtractor;
-import org.drools.base.facttemplates.FactTemplateImpl;
-import org.drools.base.facttemplates.FactTemplateObjectType;
-import org.drools.base.facttemplates.FieldTemplate;
-import org.drools.base.facttemplates.FieldTemplateImpl;
-import org.drools.base.rule.Declaration;
-import org.drools.base.rule.Pattern;
-import org.drools.base.rule.accessor.ReadAccessor;
-import org.drools.core.reteoo.CoreComponentFactory;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class FactTemplateFieldExtractorTest {
-    @Test
-    public void testExtractor() {
-        InternalKnowledgePackage pkg = CoreComponentFactory.get().createKnowledgePackage( "org.store" );
-
-        final FieldTemplate cheeseName = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields = new FieldTemplate[]{cheeseName, cheesePrice};
-        final FactTemplate cheese = new FactTemplateImpl( pkg, "Cheese", fields );
-
-        final ReadAccessor extractName = new FactTemplateFieldExtractor( cheese, "name" );
-        final ReadAccessor extractPrice = new FactTemplateFieldExtractor( cheese, "price" );
-
-        final Fact stilton = cheese.createFact();
-        stilton.set( "name", "stilton" );
-        stilton.set( "price", 200 );
-
-        assertThat(extractName.getValue(null, stilton)).isEqualTo("stilton");
-
-        assertThat(extractPrice.getValue(null, stilton)).isEqualTo(200);
-
-        assertThat(extractName.isNullValue(null, stilton)).isFalse();
-        
-        stilton.set( "name", null );
-
-        assertThat(extractName.isNullValue(null, stilton)).isTrue();
-        assertThat(extractPrice.isNullValue(null, stilton)).isFalse();
-        
-        final Fact brie = cheese.createFact();
-        brie.set( "name", "brie" );
-        brie.set( "price", 55 );
-
-        assertThat(extractName.getValue(null, brie)).isEqualTo("brie");
-
-        assertThat(extractPrice.getValue(null, brie)).isEqualTo(55);
-
-        assertThat(extractName.isNullValue(null, brie)).isFalse();
-        
-        brie.set( "name", null );
-
-        assertThat(extractName.isNullValue(null, brie)).isTrue();
-        assertThat(extractPrice.isNullValue(null, stilton)).isFalse();
-    }
-
-    @Test
-    public void testDeclaration() {
-        InternalKnowledgePackage pkg = CoreComponentFactory.get().createKnowledgePackage( "org.store" );
-
-        final FieldTemplate cheeseName = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields = new FieldTemplate[]{cheeseName, cheesePrice};
-        final FactTemplate cheese = new FactTemplateImpl( pkg,
-                                                          "Cheese",
-                                                          fields );
-
-        final ReadAccessor extractName = new FactTemplateFieldExtractor( cheese, "name" );
-
-        final Pattern pattern = new Pattern( 0,
-                                          new FactTemplateObjectType( cheese ) );
-
-        final Declaration declaration = new Declaration( "typeOfCheese",
-                                                         extractName,
-                                                         pattern );
-
-        final Fact brie = cheese.createFact();
-        brie.set( "name", "brie" );
-        brie.set( "price", 55 );
-
-        // Check we can extract Declarations correctly 
-        assertThat(declaration.getValue(null, brie)).isEqualTo("brie");
-    }
-}
diff --git a/drools-core/src/test/java/org/drools/core/facttemplates/FactTemplateTest.java b/drools-core/src/test/java/org/drools/core/facttemplates/FactTemplateTest.java
deleted file mode 100644
index a2335299f7..0000000000
--- a/drools-core/src/test/java/org/drools/core/facttemplates/FactTemplateTest.java
+++ /dev/null
@@ -1,120 +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.drools.core.facttemplates;
-
-import org.drools.base.definitions.InternalKnowledgePackage;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateImpl;
-import org.drools.base.facttemplates.FieldTemplate;
-import org.drools.base.facttemplates.FieldTemplateImpl;
-import org.drools.core.reteoo.CoreComponentFactory;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class FactTemplateTest {
-    @Test
-    public void testFieldsAndGetters() {
-        InternalKnowledgePackage pkg = CoreComponentFactory.get().createKnowledgePackage( "org.store" );
-        final FieldTemplate cheeseName = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields = new FieldTemplate[]{cheeseName, cheesePrice};
-        final FactTemplate cheese = new FactTemplateImpl( pkg,
-                                                          "Cheese",
-                                                          fields );
-
-        assertThat(cheese.getPackage().getName()).isEqualTo("org.store");
-        assertThat(cheese.getName()).isEqualTo("Cheese");
-
-        assertThat(cheese.getNumberOfFields()).isEqualTo(2);
-
-        assertThat(cheese.getFieldTemplate("name")).isSameAs(cheeseName);
-        assertThat(cheese.getFieldTemplate("price")).isSameAs(cheesePrice);
-
-        assertThat(cheese.getFieldTemplateIndex("name")).isEqualTo(0);
-        assertThat(cheese.getFieldTemplateIndex("price")).isEqualTo(1);
-    }
-
-    @Test
-    public void testEqualsAndHashCode() {
-        InternalKnowledgePackage pkg = CoreComponentFactory.get().createKnowledgePackage( "org.store" );
-
-        // Create cheese1 with name and price fields
-        final FieldTemplate cheeseName = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields1 = new FieldTemplate[]{cheeseName, cheesePrice};
-        final FactTemplate cheese1 = new FactTemplateImpl( pkg,
-                                                           "Cheese",
-                                                           fields1 );
-
-        // Create cheese2 with type and price fields
-        final FieldTemplate cheeseType = new FieldTemplateImpl( "type", String.class );
-        final FieldTemplate[] fields2 = new FieldTemplate[]{cheeseType, cheesePrice};
-        final FactTemplate cheese2 = new FactTemplateImpl( pkg,
-                                                           "Cheese",
-                                                           fields2 );
-
-        assertThat(cheese1).isNotSameAs(cheese2);
-        assertThat(cheese1).isNotEqualTo(cheese2);
-        assertThat(cheese1).doesNotHaveSameHashCodeAs(cheese2);
-
-        // create cheese3 with name and price fields, using new instances
-        final FieldTemplate cheeseName2 = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice2 = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields3 = new FieldTemplate[]{cheeseName2, cheesePrice2};
-        final FactTemplate cheese3 = new FactTemplateImpl( pkg,
-                                                           "Cheese",
-                                                           fields3 );
-
-        assertThat(cheese1).isNotSameAs(cheese3);
-        assertThat(cheese3).isEqualTo(cheese1);
-        assertThat(cheese3).hasSameHashCodeAs(cheese1);
-    }
-
-    @Test
-    public void testFacts() {
-        InternalKnowledgePackage pkg = CoreComponentFactory.get().createKnowledgePackage( "org.store" );
-        final FieldTemplate cheeseName = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields1 = new FieldTemplate[]{cheeseName, cheesePrice};
-        final FactTemplate cheese1 = new FactTemplateImpl( pkg,
-                                                           "Cheese",
-                                                           fields1 );
-
-        final Fact stilton1 = cheese1.createFact();
-        stilton1.set( "name", "stilton" );
-        stilton1.set( "price", 200 );
-
-        final Fact stilton2 = cheese1.createFact();
-        stilton2.set( "name", "stilton" );
-        stilton2.set( "price",  200 );
-
-        assertThat(stilton2).isEqualTo(stilton1);
-        assertThat(stilton2.hashCode()).isEqualTo(stilton1.hashCode());
-
-        final Fact brie = cheese1.createFact();
-        brie.set( "name", "brie" );
-        brie.set( "price", 55 );
-
-        assertThat(stilton1).isNotEqualTo(brie);
-        assertThat(stilton1).doesNotHaveSameHashCodeAs(brie);
-
-    }
-}
diff --git a/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test1.yml b/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test1.yml
index 6fbdcaf860..0e652f88ff 100644
--- a/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test1.yml
+++ b/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test1.yml
@@ -1,5 +1,6 @@
 ---
 name: mypkg
+dialect: java
 imports:
 - java.lang.Number
 - java.lang.Long
diff --git a/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test2.drl.txt b/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test2.drl.txt
index 24d576d4ba..0694efdf5f 100644
--- a/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test2.drl.txt
+++ b/drools-drlonyaml-parent/drools-drlonyaml-cli-tests/src/test/resources/expected/test2.drl.txt
@@ -1,5 +1,6 @@
 // This file was automatically generated from a YAML representation.
 package mypkg;
+dialect "java";
 import java.lang.Number;
 import java.lang.Long;
 rule "R1"
diff --git a/drools-drlonyaml-parent/drools-drlonyaml-integration-tests/src/test/java/org/drools/drlonyaml/integration/tests/ProgrammaticProjectTest.java b/drools-drlonyaml-parent/drools-drlonyaml-integration-tests/src/test/java/org/drools/drlonyaml/integration/tests/ProgrammaticProjectTest.java
index b9259d09f1..9496a73943 100644
--- a/drools-drlonyaml-parent/drools-drlonyaml-integration-tests/src/test/java/org/drools/drlonyaml/integration/tests/ProgrammaticProjectTest.java
+++ b/drools-drlonyaml-parent/drools-drlonyaml-integration-tests/src/test/java/org/drools/drlonyaml/integration/tests/ProgrammaticProjectTest.java
@@ -83,33 +83,35 @@ public class ProgrammaticProjectTest {
     }
 
     private String getDrlRule() {
-        return "package org.drools.drlonyaml.integration.tests\n" +
-                "\n" +
-                "global java.util.List result;\n" +
-                "\n" +
-                "rule R when\n" +
-                "    $i : Integer()\n" +
-                "    $m : Message( size == $i )\n" +
-                "then\n" +
-                "    result.add( $m.getText() );\n" +
-                "end";
+        return """
+                package org.drools.drlonyaml.integration.tests
+
+                global java.util.List result;
+
+                rule R when
+                    $i : Integer()
+                    $m : Message( size == $i )
+                then
+                    result.add( $m.getText() );
+                end""";
     }
 
     private String getYamlRule() {
-        return "name: org.drools.drlonyaml.integration.tests\n" +
-                "globals:\n" +
-                "- type: java.util.List\n" +
-                "  id: result\n" +
-                "rules:\n" +
-                "- name: R\n" +
-                "  when:\n" +
-                "  - given: Integer\n" +
-                "    as: $i\n" +
-                "  - given: Message\n" +
-                "    as: $m\n" +
-                "    having:\n" +
-                "    - size == $i\n" +
-                "  then: |\n" +
-                "    result.add( $m.getText() );";
+        return """
+                name: org.drools.drlonyaml.integration.tests
+                globals:
+                - type: java.util.List
+                  id: result
+                rules:
+                - name: R
+                  when:
+                  - given: Integer
+                    as: $i
+                  - given: Message
+                    as: $m
+                    having:
+                    - size == $i
+                  then: |
+                    result.add( $m.getText() );""";
     }
 }
diff --git a/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/java/org/drools/drlonyaml/model/DrlPackage.java b/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/java/org/drools/drlonyaml/model/DrlPackage.java
index dd578aa22f..097dc884f2 100644
--- a/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/java/org/drools/drlonyaml/model/DrlPackage.java
+++ b/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/java/org/drools/drlonyaml/model/DrlPackage.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
+import org.drools.drl.ast.descr.AttributeDescr;
 import org.drools.drl.ast.descr.FunctionDescr;
 import org.drools.drl.ast.descr.GlobalDescr;
 import org.drools.drl.ast.descr.ImportDescr;
@@ -32,11 +33,13 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 
-@JsonPropertyOrder({"name", "imports", "globals", "rules", "functions"})
+@JsonPropertyOrder({"name", "dialect", "imports", "globals", "rules", "functions"})
 public class DrlPackage {
     @JsonInclude(Include.NON_EMPTY)
     private String name = ""; // default empty, consistent with DRL parser.
     @JsonInclude(Include.NON_EMPTY)
+    private String dialect = "java";
+    @JsonInclude(Include.NON_EMPTY)
     private List<Import> imports = new ArrayList<>();
     @JsonInclude(Include.NON_EMPTY)
     private List<Global> globals = new ArrayList<>();
@@ -48,6 +51,10 @@ public class DrlPackage {
         Objects.requireNonNull(o);
         DrlPackage result = new DrlPackage();
         result.name = o.getName();
+        AttributeDescr dialectAttr = o.getAttribute("dialect");
+        if (dialectAttr != null) {
+            result.dialect = dialectAttr.getValue();
+        }
         for (ImportDescr i : o.getImports()) {
             result.imports.add(Import.from(i));
         }
@@ -67,6 +74,10 @@ public class DrlPackage {
         return name;
     }
 
+    public String getDialect() {
+        return dialect;
+    }
+
     public List<Import> getImports() {
         return imports;
     }
diff --git a/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/resources/drlonyaml-schema.json b/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/resources/drlonyaml-schema.json
index 82d153571e..0e44db5a4d 100644
--- a/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/resources/drlonyaml-schema.json
+++ b/drools-drlonyaml-parent/drools-drlonyaml-model/src/main/resources/drlonyaml-schema.json
@@ -163,6 +163,9 @@
     "name" : {
       "type" : "string"
     },
+    "dialect" : {
+      "type" : "string"
+    },
     "imports" : {
       "type" : "array",
       "items" : {
diff --git a/drools-drlonyaml-parent/drools-drlonyaml-todrl/src/main/resources/drl.ftl b/drools-drlonyaml-parent/drools-drlonyaml-todrl/src/main/resources/drl.ftl
index bf32316784..44b68a9592 100644
--- a/drools-drlonyaml-parent/drools-drlonyaml-todrl/src/main/resources/drl.ftl
+++ b/drools-drlonyaml-parent/drools-drlonyaml-todrl/src/main/resources/drl.ftl
@@ -1,5 +1,6 @@
 // This file was automatically generated from a YAML representation.
 <#if name?has_content>package ${name};</#if>
+<#if dialect?has_content>dialect "${dialect}";</#if>
 <#--
 
 ## DRL imports
diff --git a/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/PackageParser.java b/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/PackageParser.java
index c0615b2732..c60e69393c 100644
--- a/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/PackageParser.java
+++ b/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/PackageParser.java
@@ -32,6 +32,8 @@ import org.drools.model.codegen.execmodel.generator.RuleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.drools.model.codegen.execmodel.generator.RuleContext.DIALECT_ATTRIBUTE;
+
 public class PackageParser {
 
     Logger logger = LoggerFactory.getLogger(PackageParser.class);
@@ -59,7 +61,7 @@ public class PackageParser {
     private Rule parseRule( RuleDescr ruleDescr ) {
         RuleContext context = new ImpactAnalysisRuleContext(kbuilder, packageModel, pkgRegistry.getTypeResolver(), ruleDescr);
         context.addGlobalDeclarations();
-        context.setDialectFromAttributes( packageDescr.getAttributes() );
+        context.setDialectFromAttribute( packageDescr.getAttribute( DIALECT_ATTRIBUTE ) );
         Rule rule = new Rule( packageDescr.getName(), ruleDescr.getName(), ruleDescr.getResource().getSourcePath() );
 
         logger.debug("Parsing : " + rule.getName());
diff --git a/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/RhsParser.java b/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/RhsParser.java
index 5847149018..d11ef174a0 100644
--- a/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/RhsParser.java
+++ b/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/impl/RhsParser.java
@@ -43,7 +43,7 @@ import org.drools.impact.analysis.model.right.ModifiedMapProperty;
 import org.drools.impact.analysis.model.right.ModifiedProperty;
 import org.drools.impact.analysis.model.right.ModifyAction;
 import org.drools.model.codegen.execmodel.generator.Consequence;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
 
 import static org.drools.util.StringUtils.ucFirst;
@@ -97,7 +97,7 @@ public class RhsParser {
         Expression actionArg = statement.getArgument(0);
         Class<?> actionClass = null;
         if (actionArg.isNameExpr()) {
-            actionClass = context.getDeclarationById(actionArg.toString()).map(DeclarationSpec::getDeclarationClass)
+            actionClass = context.getTypedDeclarationById(actionArg.toString()).map(TypedDeclarationSpec::getDeclarationClass)
                     .orElseGet(() -> getClassFromAssignment(consequenceExpr, actionArg));
         } else if (actionArg.isLiteralExpr()) {
             actionClass = literalType(actionArg.asLiteralExpr());
@@ -175,7 +175,7 @@ public class RhsParser {
 
     private ModifyAction processModify( RuleContext context, MethodCallExpr consequenceExpr, MethodCallExpr statement, BlockStmt ruleVariablesBlock ) {
         String modifiedId = statement.getArgument( 0 ).toString();
-        Class<?> modifiedClass = context.getDeclarationById( modifiedId ).orElseThrow( () -> new RuntimeException("Unknown declaration: " + modifiedId) ).getDeclarationClass();
+        Class<?> modifiedClass = context.getTypedDeclarationById(modifiedId ).orElseThrow(() -> new RuntimeException("Unknown declaration: " + modifiedId) ).getDeclarationClass();
 
         ModifyAction action = new ModifyAction(modifiedClass);
 
diff --git a/drools-kiesession/src/main/java/org/drools/kiesession/entrypoints/NamedEntryPoint.java b/drools-kiesession/src/main/java/org/drools/kiesession/entrypoints/NamedEntryPoint.java
index 0cf93817c8..e83bdc4b28 100644
--- a/drools-kiesession/src/main/java/org/drools/kiesession/entrypoints/NamedEntryPoint.java
+++ b/drools-kiesession/src/main/java/org/drools/kiesession/entrypoints/NamedEntryPoint.java
@@ -18,9 +18,19 @@
  */
 package org.drools.kiesession.entrypoints;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.drools.base.definitions.rule.impl.RuleImpl;
-import org.drools.base.facttemplates.Fact;
 import org.drools.base.rule.EntryPointId;
 import org.drools.base.rule.TypeDeclaration;
 import org.drools.core.RuleBaseConfiguration;
@@ -52,22 +62,11 @@ import org.drools.core.rule.consequence.InternalMatch;
 import org.drools.util.bitmask.AllSetBitMask;
 import org.drools.util.bitmask.BitMask;
 import org.kie.api.conf.KieBaseMutabilityOption;
+import org.kie.api.prototype.PrototypeFactInstance;
 import org.kie.api.runtime.rule.FactHandle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
 import static java.util.Arrays.asList;
 import static org.drools.base.reteoo.PropertySpecificUtil.allSetBitMask;
 import static org.drools.base.reteoo.PropertySpecificUtil.calculatePositiveMask;
@@ -303,9 +302,9 @@ public class NamedEntryPoint implements InternalWorkingMemoryEntryPoint, Propert
         List<String> accessibleProperties;
         boolean isPropertyReactive;
 
-        if (object instanceof Fact) {
-            accessibleProperties = new ArrayList<>(((Fact) object).getFactTemplate().getFieldNames());
-            modifiedTypeName = ((Fact) object).getFactTemplate().getName();
+        if (object instanceof PrototypeFactInstance p) {
+            accessibleProperties = new ArrayList<>(p.getPrototype().getFieldNames());
+            modifiedTypeName = p.getPrototype().getFullName();
             isPropertyReactive = !accessibleProperties.isEmpty();
         } else {
             Class<?> modifiedClass = object.getClass();
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeFactFactory.java b/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeFactFactory.java
deleted file mode 100644
index 0843ccb4b1..0000000000
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeFactFactory.java
+++ /dev/null
@@ -1,51 +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.drools.model;
-
-import java.util.Map;
-import java.util.ServiceLoader;
-
-public interface PrototypeFactFactory {
-
-    PrototypeFact createMapBasedFact(Prototype prototype);
-
-    PrototypeFact createMapBasedFact(Prototype prototype, Map<String, Object> valuesMap);
-
-    static PrototypeFactFactory get() {
-        return Factory.get();
-    }
-
-    /**
-     * A Factory for this KieServices
-     */
-    class Factory {
-
-        private static class LazyHolder {
-            private static PrototypeFactFactory INSTANCE = ServiceLoader.load(PrototypeFactFactory.class)
-                    .findFirst().orElseThrow(() -> new RuntimeException("Unable to fine PrototypeFactFactory service, is drools-model-compiler on the classpath?"));
-        }
-
-        /**
-         * Returns a reference to the KieServices singleton
-         */
-        public static PrototypeFactFactory get() {
-            return LazyHolder.INSTANCE;
-        }
-    }
-}
\ No newline at end of file
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/Variable.java b/drools-model/drools-canonical-model/src/main/java/org/drools/model/Variable.java
index efb0b28af5..1afc5efff1 100644
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/Variable.java
+++ b/drools-model/drools-canonical-model/src/main/java/org/drools/model/Variable.java
@@ -25,4 +25,8 @@ public interface Variable<T> extends Argument<T> {
     default boolean isFact() {
         return true;
     }
+
+    default boolean isPrototype() {
+        return false;
+    }
 }
diff --git a/drools-model/drools-model-codegen/pom.xml b/drools-model/drools-model-codegen/pom.xml
index ae5732e79b..b8df4eda91 100644
--- a/drools-model/drools-model-codegen/pom.xml
+++ b/drools-model/drools-model-codegen/pom.xml
@@ -77,6 +77,10 @@
             <groupId>org.drools</groupId>
             <artifactId>drools-model-compiler</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-model-prototype</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>com.github.javaparser</groupId>
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/PackageModel.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/PackageModel.java
index 530da853b3..530b3e9b9c 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/PackageModel.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/PackageModel.java
@@ -18,6 +18,21 @@
  */
 package org.drools.model.codegen.execmodel;
 
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
 import com.github.javaparser.StaticJavaParser;
 import com.github.javaparser.ast.CompilationUnit;
 import com.github.javaparser.ast.ImportDeclaration;
@@ -50,6 +65,7 @@ import org.drools.codegen.common.DroolsModelBuildContext;
 import org.drools.compiler.builder.impl.BuildResultCollector;
 import org.drools.compiler.builder.impl.KnowledgeBuilderConfigurationImpl;
 import org.drools.compiler.builder.impl.KnowledgeBuilderImpl;
+import org.drools.compiler.builder.impl.KnowledgeBuilderRulesConfigurationImpl;
 import org.drools.compiler.builder.impl.TypeDeclarationContext;
 import org.drools.compiler.builder.impl.TypeDeclarationUtils;
 import org.drools.compiler.compiler.DialectCompiletimeRegistry;
@@ -77,25 +93,11 @@ import org.drools.modelcompiler.util.StringUtil;
 import org.drools.util.StringUtils;
 import org.drools.util.TypeResolver;
 import org.kie.api.builder.ReleaseId;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.runtime.rule.AccumulateFunction;
 import org.kie.internal.ruleunit.RuleUnitDescription;
 import org.kie.internal.ruleunit.RuleUnitVariable;
 
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
 import static com.github.javaparser.StaticJavaParser.parseBodyDeclaration;
 import static com.github.javaparser.ast.Modifier.finalModifier;
 import static com.github.javaparser.ast.Modifier.publicModifier;
@@ -182,6 +184,8 @@ public class PackageModel {
     private final String executableRulesClass;
     private final Collection<String> executableRulesClasses = new HashSet<>();
 
+    private final boolean prototypesAllowed;
+
     private PackageModel( ReleaseId releaseId, String name, KnowledgeBuilderConfigurationImpl configuration, DialectCompiletimeRegistry dialectCompiletimeRegistry, DRLIdGenerator exprIdGenerator) {
         this(name, configuration, dialectCompiletimeRegistry, exprIdGenerator, getPkgUUID(releaseId, name));
     }
@@ -197,8 +201,9 @@ public class PackageModel {
         this.configuration = configuration;
         this.exprIdGenerator = exprIdGenerator;
         this.dialectCompiletimeRegistry = dialectCompiletimeRegistry;
-        executableRulesClass = name + "."  + rulesFileName;
-        executableRulesClasses.add(executableRulesClass);
+        this.executableRulesClass = name + "."  + rulesFileName;
+        this.executableRulesClasses.add(executableRulesClass);
+        this.prototypesAllowed = configuration != null && configuration.as(KnowledgeBuilderRulesConfigurationImpl.KEY).getPrototypesOption() == PrototypesOption.ALLOWED;
     }
 
     public static PackageModel createPackageModel(KnowledgeBuilderConfigurationImpl configuration, PackageDescr packageDescr, PackageRegistry pkgRegistry, String pkgName, ReleaseId releaseId, DRLIdGenerator exprIdGenerator) {
@@ -942,6 +947,10 @@ public class PackageModel {
         return otnsClasses;
     }
 
+    public boolean arePrototypesAllowed() {
+        return prototypesAllowed;
+    }
+
     public String getDomainClassesMetadataSource() {
         StringBuilder sb = new StringBuilder(
                 "package " + name + ";\n" +
@@ -1048,4 +1057,9 @@ public class PackageModel {
         final Map<String, java.lang.reflect.Type> globals = new HashMap<>();
         final Set<String> entryPoints = new HashSet<>();
     }
+
+    @Override
+    public String toString() {
+        return pkg.toString();
+    }
 }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/AggregateKey.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/AggregateKey.java
index 0ee30f6f90..2b03cf5cc6 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/AggregateKey.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/AggregateKey.java
@@ -18,33 +18,5 @@
  */
 package org.drools.model.codegen.execmodel.generator;
 
-import java.util.Objects;
-
-public final class AggregateKey {
-    String key;
-    Class<?> clazz;
-
-    public AggregateKey(String key, Class<?> clazz) {
-        this.key = key;
-        this.clazz = clazz;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        AggregateKey that = (AggregateKey) o;
-        return key.equals(that.key) &&
-                clazz.equals(that.clazz);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(key, clazz);
-    }
-}
+public record AggregateKey(String key, String type) { }
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/BoxedParameters.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/BoxedParameters.java
index d76cc757a2..a681ee3d75 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/BoxedParameters.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/BoxedParameters.java
@@ -23,15 +23,17 @@ import java.util.Collection;
 import com.github.javaparser.ast.NodeList;
 import com.github.javaparser.ast.body.Parameter;
 import com.github.javaparser.ast.body.VariableDeclarator;
-import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.NameExpr;
 import com.github.javaparser.ast.expr.VariableDeclarationExpr;
 import com.github.javaparser.ast.stmt.BlockStmt;
 import com.github.javaparser.ast.type.Type;
+import org.kie.api.prototype.PrototypeFactInstance;
+
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
 
 public class BoxedParameters {
 
-    RuleContext context;
+    private final RuleContext context;
 
     public BoxedParameters(RuleContext context) {
         this.context = context;
@@ -40,27 +42,35 @@ public class BoxedParameters {
     // Types in the executable model are promoted to boxed to type check the Java DSL.
     // We add such promoted types as _<PARAMETER_NAME> (with the underscore prefix)
     // and then we downcast to the original unboxed type in the body of the function (methodBody)
-    public NodeList<Parameter> getBoxedParametersWithUnboxedAssignment(Collection<String> declarationUsedInRHS,
-                                                                       BlockStmt methodBody) {
-
+    public NodeList<Parameter> getBoxedParametersWithUnboxedAssignment(Collection<String> declarationUsedInRHS, BlockStmt methodBody) {
         NodeList<Parameter> parameters = NodeList.nodeList();
-
         for (String parameterName : declarationUsedInRHS) {
-            DeclarationSpec declaration = context.getDeclarationByIdWithException(parameterName);
+            TypedDeclarationSpec declaration = context.getTypedDeclarationByIdWithException(parameterName);
+            Parameter boxedParameter = getTypedParameter(methodBody, parameterName, declaration);
+            parameters.add(boxedParameter);
+        }
+        return parameters;
+    }
+
+    private static Parameter getTypedParameter(BlockStmt methodBody, String parameterName, TypedDeclarationSpec declaration) {
+        Type boxedType = declaration.getBoxedType();
+        if (!declaration.isBoxed()) {
+            return new Parameter(boxedType, parameterName);
+        }
 
-            Parameter boxedParameter;
-            Type boxedType = declaration.getBoxedType();
+        String boxedParameterName = "_" + parameterName;
+        VariableDeclarator varDec = new VariableDeclarator(declaration.getRawType(), parameterName, new NameExpr(boxedParameterName));
+        methodBody.addStatement(0, new VariableDeclarationExpr(varDec));
+        return new Parameter(boxedType, boxedParameterName);
+    }
 
-            if (declaration.isBoxed()) {
-                String boxedParameterName = "_" + parameterName;
-                boxedParameter = new Parameter(boxedType, boxedParameterName);
-                Expression unboxedTypeDowncast = new VariableDeclarationExpr(new VariableDeclarator(declaration.getRawType(),
-                                                                                                    parameterName,
-                                                                                                    new NameExpr(boxedParameterName)));
-                methodBody.addStatement(0, unboxedTypeDowncast);
-            } else {
-                boxedParameter = new Parameter(boxedType, parameterName);
-            }
+    public NodeList<Parameter> getParametersForPrototype(Collection<String> declarationUsedInRHS, BlockStmt methodBody) {
+        NodeList<Parameter> parameters = NodeList.nodeList();
+        for (String parameterName : declarationUsedInRHS) {
+            DeclarationSpec declaration = context.getDeclarationByIdWithException(parameterName);
+            Parameter boxedParameter = declaration instanceof TypedDeclarationSpec tSpec ?
+                    getTypedParameter(methodBody, parameterName, tSpec) :
+                    new Parameter(toClassOrInterfaceType(PrototypeFactInstance.class), parameterName);
             parameters.add(boxedParameter);
         }
         return parameters;
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/Consequence.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/Consequence.java
index bdd8282553..9ce2ebd940 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/Consequence.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/Consequence.java
@@ -48,9 +48,9 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr;
 import com.github.javaparser.ast.stmt.BlockStmt;
 import com.github.javaparser.ast.stmt.ExpressionStmt;
 import com.github.javaparser.ast.type.Type;
+import org.drools.base.factmodel.ClassDefinition;
 import org.drools.compiler.compiler.MissingDependencyError;
 import org.drools.core.common.TruthMaintenanceSystemFactory;
-import org.drools.base.factmodel.ClassDefinition;
 import org.drools.model.BitMask;
 import org.drools.model.bitmask.AllSetButLastBitMask;
 import org.drools.model.codegen.execmodel.PackageModel;
@@ -60,8 +60,8 @@ import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
 import org.drools.model.codegen.execmodel.errors.MvelCompilationError;
 import org.drools.modelcompiler.consequence.DroolsImpl;
 import org.drools.mvelcompiler.CompiledBlockResult;
-import org.drools.mvelcompiler.PreprocessCompiler;
 import org.drools.mvelcompiler.MvelCompilerException;
+import org.drools.mvelcompiler.PreprocessCompiler;
 import org.drools.util.StringUtils;
 
 import static com.github.javaparser.StaticJavaParser.parseExpression;
@@ -260,7 +260,7 @@ public class Consequence {
 
         if (context.getRuleDialect() == RuleContext.RuleDialect.MVEL) {
             return existingDecls.stream().filter(d -> containsWord(d, consequenceString)).collect(toSet());
-        } else if (context.getRuleDialect() == RuleContext.RuleDialect.JAVA) {
+        } else if (ruleConsequence != null) {
             Set<String> declUsedInRHS = ruleConsequence.findAll(NameExpr.class).stream().map(NameExpr::getNameAsString).collect(toSet());
             return existingDecls.stream().filter(declUsedInRHS::contains).collect(toSet());
         }
@@ -288,7 +288,9 @@ public class Consequence {
             executeLambda.addParameter(new Parameter(toClassOrInterfaceType(org.drools.model.Drools.class), "drools"));
         }
 
-        NodeList<Parameter> parameters = new BoxedParameters(context).getBoxedParametersWithUnboxedAssignment(verifiedDeclUsedInRHS, ruleConsequence);
+        NodeList<Parameter> parameters = context.arePrototypesAllowed() ?
+                new BoxedParameters(context).getParametersForPrototype(verifiedDeclUsedInRHS, ruleConsequence) :
+                new BoxedParameters(context).getBoxedParametersWithUnboxedAssignment(verifiedDeclUsedInRHS, ruleConsequence);
         parameters.forEach(executeLambda::addParameter);
 
         executeLambda.setBody(ruleConsequence);
@@ -308,13 +310,14 @@ public class Consequence {
     private String preprocessConsequence(String consequence) {
         int modifyPos = StringUtils.indexOfOutOfQuotes(consequence, "modify");
         int textBlockPos = StringUtils.indexOfOutOfQuotes(consequence, "\"\"\"");
+        Set<String> prototypes = context.getPrototypeDeclarations();
 
-        if (modifyPos < 0 && textBlockPos < 0) {
+        if (modifyPos < 0 && textBlockPos < 0 && prototypes.isEmpty()) {
             return consequence;
         }
 
         PreprocessCompiler preprocessCompiler = new PreprocessCompiler();
-        CompiledBlockResult compile = preprocessCompiler.compile(addCurlyBracesToBlock(consequence));
+        CompiledBlockResult compile = preprocessCompiler.compile(addCurlyBracesToBlock(consequence), prototypes);
 
         return printNode(compile.statementResults());
     }
@@ -421,8 +424,8 @@ public class Consequence {
                 throw new ConsequenceRewriteException();
             }
         } else {
-            return context.getDeclarationById(updatedVar)
-                    .map(DeclarationSpec::getDeclarationClass)
+            return context.getTypedDeclarationById(updatedVar)
+                    .map(TypedDeclarationSpec::getDeclarationClass)
                     .orElseThrow(ConsequenceRewriteException::new);
         }
     }
@@ -527,8 +530,8 @@ public class Consequence {
     }
 
     private boolean isDataStoreScope(Expression scope) {
-        return scope.isNameExpr() && context.getDeclarationById(scope.asNameExpr().getNameAsString())
-                .map(DeclarationSpec::getDeclarationClass)
+        return scope.isNameExpr() && context.getTypedDeclarationById(scope.asNameExpr().getNameAsString())
+                .map(TypedDeclarationSpec::getDeclarationClass)
                 .map(dataStoreClass::isAssignableFrom).orElse(false);
     }
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java
index f8d01f49b1..29e650c187 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java
@@ -18,156 +18,27 @@
  */
 package org.drools.model.codegen.execmodel.generator;
 
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Collections;
-import java.util.List;
 import java.util.Optional;
 
-import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.MethodCallExpr;
-import org.drools.base.base.ClassObjectType;
-import org.drools.base.rule.Declaration;
-import org.drools.base.rule.accessor.PatternExtractor;
-import org.drools.drl.ast.descr.BehaviorDescr;
-import org.drools.drl.ast.descr.EntryPointDescr;
-import org.drools.drl.ast.descr.PatternDescr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import org.drools.model.codegen.execmodel.PackageModel;
 
-import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
-import static org.drools.util.ClassUtils.rawType;
+public interface DeclarationSpec {
+    String getBindingId();
 
-public class DeclarationSpec {
-    private final String bindingId;
-    private final Type declarationType;
-    private final Optional<PatternDescr> optPattern;
-    private final Optional<Expression> declarationSource;
-    private final Optional<String> variableName;
-    private final boolean isGlobal;
+    Optional<String> getVariableName();
 
-    private String boundVariable;
-    private MethodCallExpr bindingExpr;
-    private boolean boxed = false;
-    private Optional<PatternDescr> belongingPatternDescr = Optional.empty();
+    Class<?> getDeclarationClass();
 
-    public DeclarationSpec(String bindingId, Type declarationType) {
-        this(bindingId, declarationType, Optional.empty(), Optional.empty(), Optional.empty(), false);
-    }
-
-    public DeclarationSpec(String bindingId, Type declarationType, boolean isGlobal) {
-        this(bindingId, declarationType, Optional.empty(), Optional.empty(), Optional.empty(), isGlobal);
-    }
-
-    DeclarationSpec(String bindingId, Type declarationType, String variableName) {
-        this(bindingId, declarationType, Optional.empty(), Optional.empty(), Optional.of(variableName), false);
-    }
-
-    DeclarationSpec(String bindingId, Type declarationType, Expression declarationSource) {
-        this(bindingId, declarationType, Optional.empty(), Optional.of(declarationSource), Optional.empty(), false);
-    }
-
-    DeclarationSpec(String bindingId, Type declarationType, Optional<PatternDescr> pattern, Optional<Expression> declarationSource, Optional<String> variableName, boolean isGlobal) {
-        this.bindingId = bindingId;
-        this.declarationType = declarationType;
-        this.optPattern = pattern;
-        this.declarationSource = declarationSource;
-        this.variableName = variableName;
-        this.isGlobal = isGlobal;
-    }
-
-    Optional<String> getEntryPoint() {
-        return optPattern.flatMap(pattern -> pattern.getSource() instanceof EntryPointDescr ?
-                Optional.of(((EntryPointDescr) pattern.getSource()).getEntryId()) :
-                Optional.empty()
-        );
-    }
-
-    public List<BehaviorDescr> getBehaviors() {
-        return optPattern.map(PatternDescr::getBehaviors).orElse(Collections.emptyList());
-    }
-
-    public String getBindingId() {
-        return bindingId;
-    }
-
-    public Class<?> getDeclarationClass() {
-        return rawType( declarationType );
-    }
-
-    public Type getDeclarationType() {
-        return declarationType;
-    }
-
-    public boolean isParametrizedType() {
-        return declarationType instanceof ParameterizedType;
-    }
-
-    public Optional<Expression> getDeclarationSource() {
-        return declarationSource;
-    }
-
-    public Optional<String> getVariableName() {
-        return variableName;
-    }
-
-    public com.github.javaparser.ast.type.Type getBoxedType() {
-        return DrlxParseUtil.classToReferenceType(this);
-    }
-
-    public com.github.javaparser.ast.type.Type getRawType() {
-        return toClassOrInterfaceType(getDeclarationClass());
-    }
-
-    public boolean isGlobal() {
-        return isGlobal;
-    }
-
-    public Optional<String> getBoundVariable() {
-        return Optional.ofNullable( boundVariable );
-    }
-
-    public void setBoundVariable( String boundVariable ) {
-        this.boundVariable = boundVariable;
-    }
-
-    public MethodCallExpr getBindingExpr() {
-        return bindingExpr;
-    }
-
-    public void setBindingExpr( MethodCallExpr bindingExpr ) {
-        this.bindingExpr = bindingExpr;
-    }
-
-    @Override
-    public String toString() {
-        return "DeclarationSpec{" +
-                "bindingId='" + bindingId + '\'' +
-                ", declarationClass=" + declarationType +
-                ", isGlobal=" + isGlobal +
-                ", boxed=" + boxed +
-                '}';
-    }
-
-    public Declaration asDeclaration() {
-        Class<?> declarationClass = getDeclarationClass();
-        Declaration decl = new Declaration( bindingId, new PatternExtractor( new ClassObjectType(declarationClass) ), null );
-        decl.setDeclarationClass(declarationClass);
-        return decl;
-    }
-
-    public void setBoxed(boolean boxed) {
-        this.boxed = boxed;
-    }
+    boolean isGlobal();
 
-    public boolean isBoxed() {
-        return boxed;
-    }
+    MethodCallExpr getBindingExpr();
+    void setBindingExpr( MethodCallExpr bindingExpr );
 
-    public Optional<PatternDescr> getBelongingPatternDescr() {
-        return belongingPatternDescr;
-    }
+    void registerOnPackage(PackageModel packageModel, RuleContext context, BlockStmt ruleBlock);
 
-    public void setBelongingPatternDescr(Optional<PatternDescr> belongingPatternDescr) {
-        this.belongingPatternDescr = belongingPatternDescr;
+    default boolean isPrototypeDeclaration() {
+        return false;
     }
-
 }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
index 86c96ac505..b39396d8ce 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
@@ -295,7 +295,7 @@ public class DrlxParseUtil {
         if (usedDeclarations != null) {
             usedDeclarations.add(name);
         }
-        Optional<java.lang.reflect.Type> type = context.getDeclarationById( name ).map(DeclarationSpec::getDeclarationClass);
+        Optional<java.lang.reflect.Type> type = context.getTypedDeclarationById(name ).map(TypedDeclarationSpec::getDeclarationClass);
         return type.orElseThrow(() -> new NoSuchElementException("Cannot get expression type by name " + name + "!"));
     }
 
@@ -587,7 +587,7 @@ public class DrlxParseUtil {
         return classNameToReferenceTypeWithBoxing(declarationClass).parsedType;
     }
 
-    public static Type classToReferenceType(DeclarationSpec declaration) {
+    public static Type classToReferenceType(TypedDeclarationSpec declaration) {
         if (declaration.isParametrizedType()) {
             return StaticJavaParser.parseClassOrInterfaceType(declaration.getDeclarationType().getTypeName());
         }
@@ -947,7 +947,7 @@ public class DrlxParseUtil {
 
         List<DeclarationSpec> allDeclarations = new ArrayList<>(context.getAllDeclarations());
         originalPatternType.ifPresent(pt -> {
-            allDeclarations.add(new DeclarationSpec(THIS_PLACEHOLDER, pt));
+            allDeclarations.add(new TypedDeclarationSpec(THIS_PLACEHOLDER, pt));
             mvelCompilerContext.setRootPatternPrefix(pt, THIS_PLACEHOLDER);
         });
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DslMethodNames.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DslMethodNames.java
index f457cec38e..f863319ce0 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DslMethodNames.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DslMethodNames.java
@@ -22,6 +22,7 @@ import com.github.javaparser.ast.NodeList;
 import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.MethodCallExpr;
 import com.github.javaparser.ast.expr.NameExpr;
+import org.drools.model.prototype.PrototypeDSL;
 
 public class DslMethodNames {
 
@@ -70,6 +71,13 @@ public class DslMethodNames {
     public static final String EVAL_CALL = "eval";
     public static final String NO_OP_EXPR = "NO_OP_EXPR";
 
+    // prototypes
+    public static final NameExpr PROTO_DSL_NAMESPACE = new NameExpr(PrototypeDSL.class.getCanonicalName());
+    public static final String PROTO_PATTERN_CALL = "protoPattern";
+    public static final String PROTO_EXPR_CALL = "expr";
+    public static final String PROTOTYPE_FACT_CALL = "prototypeFact";
+    public static final String PROTOTYPE_VARIABLE_CALL = "variable";
+
     // expressions
     public static final String EVAL_EXPR_CALL = "expr";
     public static final String EXPR_CALL = "expr";
@@ -109,4 +117,8 @@ public class DslMethodNames {
     public static boolean isDslTopLevelNamespace(Expression expr) {
         return DSL_NAMESPACE.equals(expr);
     }
+
+    public static MethodCallExpr createProtoDslTopLevelMethod(String name) {
+        return new MethodCallExpr(PROTO_DSL_NAMESPACE.clone(), name);
+    }
 }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/ModelGenerator.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/ModelGenerator.java
index b932598ca2..517c1c403f 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/ModelGenerator.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/ModelGenerator.java
@@ -91,6 +91,7 @@ import static org.drools.model.codegen.execmodel.generator.DslMethodNames.SUPPLY
 import static org.drools.model.codegen.execmodel.generator.DslMethodNames.UNIT_CALL;
 import static org.drools.model.codegen.execmodel.generator.DslMethodNames.WINDOW_CALL;
 import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createDslTopLevelMethod;
+import static org.drools.model.codegen.execmodel.generator.RuleContext.DIALECT_ATTRIBUTE;
 import static org.drools.modelcompiler.util.ClassUtil.asJavaSourceName;
 import static org.drools.modelcompiler.util.StringUtil.toId;
 import static org.drools.modelcompiler.util.TimerUtil.validateTimer;
@@ -178,7 +179,7 @@ public class ModelGenerator {
             if (context.getRuleUnitDescr() != null) {
                 ruleUnitDescrs.add(context.getRuleUnitDescr());
             }
-            context.setDialectFromAttributes(packageDescr.getAttributes());
+            context.setDialectFromAttribute(packageDescr.getAttribute( DIALECT_ATTRIBUTE ));
             if (descr instanceof QueryDescr) {
                 QueryGenerator.processQueryDef(packageModel, context);
             }
@@ -213,7 +214,7 @@ public class ModelGenerator {
             QueryGenerator.processQuery(context.getPackageModel(), (QueryDescr) context.getRuleDescr());
             return;
         }
-        context.setDialectFromAttributes(packageDescr.getAttributes());
+        context.setDialectFromAttribute(packageDescr.getAttribute( DIALECT_ATTRIBUTE ));
         processRule(packageDescr, context);
     }
 
@@ -221,7 +222,7 @@ public class ModelGenerator {
         PackageModel packageModel = context.getPackageModel();
         RuleDescr ruleDescr = context.getRuleDescr();
         context.addGlobalDeclarations();
-        context.setDialectFromAttributes(ruleDescr.getAttributes().values());
+        context.setDialectFromAttribute(ruleDescr.getAttributes().get( DIALECT_ATTRIBUTE ));
 
         for(Entry<String, Object> kv : ruleDescr.getNamedConsequences().entrySet()) {
             context.addNamedConsequence(kv.getKey(), kv.getValue().toString());
@@ -492,58 +493,8 @@ public class ModelGenerator {
 
     public static void createVariables(BlockStmt block, PackageModel packageModel, RuleContext context) {
         for (DeclarationSpec decl : context.getAllDeclarations()) {
-            boolean domainClass = packageModel.registerDomainClass( decl.getDeclarationClass() );
-            if (!context.getGlobals().containsKey(decl.getBindingId()) && context.getQueryParameterByName(decl.getBindingId()).isEmpty()) {
-                addVariable(block, decl, context, domainClass);
-            }
+            decl.registerOnPackage(packageModel, context, block);
         }
     }
 
-    private static void addVariable(BlockStmt ruleBlock, DeclarationSpec declaration, RuleContext context, boolean domainClass) {
-        if (declaration.getDeclarationClass() == null) {
-            context.addCompilationError( new UnknownDeclarationError( declaration.getBindingId() ) );
-            return;
-        }
-        Type declType = classToReferenceType( declaration );
-
-        ClassOrInterfaceType varType = toClassOrInterfaceType(Variable.class);
-        varType.setTypeArguments(declType);
-        VariableDeclarationExpr var_ = new VariableDeclarationExpr(varType, context.getVar(declaration.getBindingId()), Modifier.finalModifier());
-
-        MethodCallExpr declarationOfCall = createDslTopLevelMethod(DECLARATION_OF_CALL);
-
-        declarationOfCall.addArgument(new ClassExpr( declaration.getBoxedType() ));
-
-        if (domainClass) {
-            String domainClassSourceName = asJavaSourceName( declaration.getDeclarationClass() );
-            declarationOfCall.addArgument( DOMAIN_CLASSESS_METADATA_FILE_NAME + context.getPackageModel().getPackageUUID() + "." + domainClassSourceName + DOMAIN_CLASS_METADATA_INSTANCE );
-        }
-
-        declarationOfCall.addArgument(toStringLiteral(declaration.getVariableName().orElse(declaration.getBindingId())));
-
-        declaration.getDeclarationSource().ifPresent(declarationOfCall::addArgument);
-
-        declaration.getEntryPoint().ifPresent( ep -> {
-            MethodCallExpr entryPointCall = createDslTopLevelMethod(ENTRY_POINT_CALL);
-            entryPointCall.addArgument( toStringLiteral(ep ) );
-            declarationOfCall.addArgument( entryPointCall );
-        } );
-        for ( BehaviorDescr behaviorDescr : declaration.getBehaviors() ) {
-            MethodCallExpr windowCall = createDslTopLevelMethod(WINDOW_CALL);
-            if ( BehaviorRuntime.BehaviorType.TIME_WINDOW.matches(behaviorDescr.getSubType()) ) {
-                windowCall.addArgument( "org.drools.model.Window.Type.TIME" );
-                windowCall.addArgument( "" + TimeUtils.parseTimeString(behaviorDescr.getParameters().get(0 ) ) );
-            }
-            if ( BehaviorRuntime.BehaviorType.LENGTH_WINDOW.matches(behaviorDescr.getSubType()) ) {
-                windowCall.addArgument( "org.drools.model.Window.Type.LENGTH" );
-                windowCall.addArgument( "" + Integer.valueOf( behaviorDescr.getParameters().get( 0 ) ) );
-            }
-            declarationOfCall.addArgument( windowCall );
-        }
-
-        AssignExpr var_assign = new AssignExpr(var_, declarationOfCall, AssignExpr.Operator.ASSIGN);
-        if (!DrlxParseUtil.hasDuplicateExpr(ruleBlock, var_assign)) {
-            ruleBlock.addStatement(var_assign);
-        }
-    }
 }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java
index 4c845e06fe..e16ba61bcf 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java
@@ -137,7 +137,7 @@ public class OOPathExprGenerator {
             bindingId = context.getOOPathId(fieldType, originalBind + fieldName + pos);
         }
 
-        DeclarationSpec newDeclaration = context.addDeclaration(bindingId, fieldType, reactiveFrom);
+        TypedDeclarationSpec newDeclaration = context.addDeclaration(bindingId, fieldType, reactiveFrom);
         context.addOOPathDeclaration(newDeclaration);
 
         final List<DrlxExpression> conditions = chunk.getConditions();
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/PrototypeDeclarationSpec.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/PrototypeDeclarationSpec.java
new file mode 100644
index 0000000000..ce7d7e171a
--- /dev/null
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/PrototypeDeclarationSpec.java
@@ -0,0 +1,82 @@
+package org.drools.model.codegen.execmodel.generator;
+
+import java.util.Optional;
+
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import org.drools.model.codegen.execmodel.PackageModel;
+import org.drools.model.prototype.PrototypeVariable;
+
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PROTOTYPE_FACT_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PROTOTYPE_VARIABLE_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createProtoDslTopLevelMethod;
+
+public class PrototypeDeclarationSpec implements DeclarationSpec {
+
+    private final String bindingId;
+    private final String prototypeType;
+    private final boolean isGlobal;
+
+    private MethodCallExpr bindingExpr;
+
+    PrototypeDeclarationSpec(String bindingId, String prototypeType, boolean isGlobal) {
+        this.bindingId = bindingId;
+        this.prototypeType = prototypeType;
+        this.isGlobal = isGlobal;
+    }
+
+    @Override
+    public String getBindingId() {
+        return bindingId;
+    }
+
+    @Override
+    public Optional<String> getVariableName() {
+        return Optional.empty();
+    }
+
+    @Override
+    public Class<?> getDeclarationClass() {
+        return null;
+    }
+
+    @Override
+    public boolean isGlobal() {
+        return isGlobal;
+    }
+
+    @Override
+    public boolean isPrototypeDeclaration() {
+        return true;
+    }
+
+    @Override
+    public MethodCallExpr getBindingExpr() {
+        return bindingExpr;
+    }
+
+    @Override
+    public void setBindingExpr( MethodCallExpr bindingExpr ) {
+        this.bindingExpr = bindingExpr;
+    }
+
+    @Override
+    public void registerOnPackage(PackageModel packageModel, RuleContext context, BlockStmt ruleBlock) {
+        ClassOrInterfaceType varType = toClassOrInterfaceType(PrototypeVariable.class);
+        VariableDeclarationExpr varExpr = new VariableDeclarationExpr(varType, context.getVar(getBindingId()), Modifier.finalModifier());
+
+        MethodCallExpr prototypeCall = createProtoDslTopLevelMethod(PROTOTYPE_FACT_CALL);
+        prototypeCall.addArgument(new StringLiteralExpr(prototypeType));
+        MethodCallExpr variableCall = createProtoDslTopLevelMethod(PROTOTYPE_VARIABLE_CALL);
+        variableCall.addArgument(prototypeCall);
+
+        AssignExpr varAssign = new AssignExpr(varExpr, variableCall, AssignExpr.Operator.ASSIGN);
+        ruleBlock.addStatement(varAssign);
+    }
+}
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/QueryGenerator.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/QueryGenerator.java
index 458e1c9e92..4e54336b6d 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/QueryGenerator.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/QueryGenerator.java
@@ -43,6 +43,7 @@ import org.drools.model.codegen.execmodel.QueryModel;
 import org.drools.model.codegen.execmodel.generator.visitor.ModelGeneratorVisitor;
 import org.kie.internal.ruleunit.RuleUnitDescription;
 
+import static org.drools.model.codegen.execmodel.generator.RuleContext.DIALECT_ATTRIBUTE;
 import static org.drools.model.impl.VariableImpl.GENERATED_VARIABLE_PREFIX;
 import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getClassFromContext;
 import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
@@ -79,9 +80,9 @@ public class QueryGenerator {
     }
 
     public static class QueryDefWithType {
-        private ClassOrInterfaceType queryType;
-        private MethodCallExpr methodCallExpr;
-        private RuleContext context;
+        private final ClassOrInterfaceType queryType;
+        private final MethodCallExpr methodCallExpr;
+        private final RuleContext context;
 
         public QueryDefWithType(ClassOrInterfaceType queryType, MethodCallExpr methodCallExpr, RuleContext contex) {
             this.queryType = queryType;
@@ -107,7 +108,7 @@ public class QueryGenerator {
         RuleContext context = packageModel.getQueryDefWithType().get(queryDefVariableName).getContext();
 
         context.addGlobalDeclarations();
-        context.setDialectFromAttributes(queryDescr.getAttributes().values());
+        context.setDialectFromAttribute(queryDescr.getAttributes().get( DIALECT_ATTRIBUTE ));
 
         new ModelGeneratorVisitor(context, packageModel).visit(queryDescr.getLhs());
         if (context.getRuleUnitDescr() != null) {
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/RuleContext.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/RuleContext.java
index 737d68a3e2..686a539b7c 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/RuleContext.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/RuleContext.java
@@ -23,6 +23,7 @@ import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -34,6 +35,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 import com.github.javaparser.ast.body.Parameter;
 import com.github.javaparser.ast.expr.Expression;
@@ -77,6 +79,8 @@ import static org.drools.util.ClassUtils.rawType;
 
 public class RuleContext {
 
+    public static final String DIALECT_ATTRIBUTE = "dialect";
+
     private static final String SCOPE_SUFFIX = "_sCoPe";
 
     private final TypeDeclarationContext typeDeclarationContext;
@@ -90,7 +94,7 @@ public class RuleContext {
 
     private final Map<String, DeclarationSpec> allDeclarations = new LinkedHashMap<>();
     private final Map<String, DeclarationSpec> scopedDeclarations = new LinkedHashMap<>();
-    private final List<DeclarationSpec> ooPathDeclarations = new ArrayList<>();
+    private final List<TypedDeclarationSpec> ooPathDeclarations = new ArrayList<>();
     private final Deque<Consumer<Expression>> exprPointer = new ArrayDeque<>();
     private final List<Expression> expressions = new ArrayList<>();
     private final Map<String, String> namedConsequences = new HashMap<>();
@@ -113,6 +117,8 @@ public class RuleContext {
 
     private RuleDialect ruleDialect = RuleDialect.JAVA; // assumed is java by default as per Drools manual.
 
+    private boolean prototypesAllowed = false;
+
     private int scopeCounter = 1;
     private Scope currentScope = new Scope();
     private final Deque<Scope> scopesStack = new LinkedList<>();
@@ -131,7 +137,21 @@ public class RuleContext {
     private boolean hasCompilationError;
 
     public enum RuleDialect {
-        JAVA, MVEL
+        JAVA, MVEL;
+
+        public static RuleDialect resolveDialect(String dialect) {
+            if (dialect == null) {
+                return JAVA;
+            }
+            switch (dialect) {
+                case "java":
+                    return JAVA;
+                case "mvel":
+                    return MVEL;
+                default:
+                    throw new IllegalArgumentException("Unknown dialect: " + dialect);
+            }
+        }
     }
 
     private AndDescr parentDescr;
@@ -145,7 +165,7 @@ public class RuleContext {
         this.resultCollector = resultCollector;
         this.packageModel = packageModel;
         this.idGenerator = packageModel.getExprIdGenerator();
-        exprPointer.push( this.expressions::add );
+        this.exprPointer.push( this.expressions::add );
         this.typeResolver = typeResolver;
         this.ruleDescr = ruleDescr;
         this.ruleUnitDescr = findUnitDescr();
@@ -224,20 +244,38 @@ public class RuleContext {
         return ofNullable(explicitCastType.get(field));
     }
 
+    public Optional<TypedDeclarationSpec> getTypedDeclarationById(String id) {
+        return getDeclarationById(id).map(TypedDeclarationSpec.class::cast);
+    }
+
+    public TypedDeclarationSpec getTypedDeclarationByIdWithException(String id) {
+        return getTypedDeclarationById(id).orElseThrow(() -> new UnknownDeclarationException("Unknown declaration: " + id));
+    }
+
     public Optional<DeclarationSpec> getDeclarationById(String id) {
-        DeclarationSpec spec = scopedDeclarations.get( getDeclarationKey( id ));
+        DeclarationSpec spec = scopedDeclarations.get(getDeclarationKey(id ));
         if (spec == null) {
             Class<?> unitVarType = ruleUnitVarsOriginalType.get( id );
             if(unitVarType == null) {
                 unitVarType = ruleUnitVars.get(id);
             }
             if (unitVarType != null) {
-                spec = new DeclarationSpec(id, unitVarType);
+                spec = new TypedDeclarationSpec(id, unitVarType);
             }
         }
         return ofNullable( spec );
     }
 
+    public boolean isPrototypeDeclaration(String id) {
+        return getDeclarationById(id).map(DeclarationSpec::isPrototypeDeclaration).orElse(false);
+    }
+
+    public Set<String> getPrototypeDeclarations() {
+        return arePrototypesAllowed() ?
+                scopedDeclarations.values().stream().filter(DeclarationSpec::isPrototypeDeclaration).map(DeclarationSpec::getBindingId).collect(Collectors.toSet()) :
+                Collections.emptySet();
+    }
+
     public DeclarationSpec getDeclarationByIdWithException(String id) {
         return getDeclarationById(id).orElseThrow(() -> new UnknownDeclarationException("Unknown declaration: " + id));
     }
@@ -289,7 +327,7 @@ public class RuleContext {
         
         for (Map.Entry<String, java.lang.reflect.Type> ks : globals.entrySet()) {
             definedVars.put(ks.getKey(), ks.getKey());
-            addDeclaration(new DeclarationSpec(ks.getKey(), ks.getValue(), true));
+            addDeclaration(new TypedDeclarationSpec(ks.getKey(), ks.getValue(), true));
         }
     }
 
@@ -312,7 +350,7 @@ public class RuleContext {
         return packageModel.hasEntryPoint(name) || (ruleUnitDescr != null && packageModel.hasEntryPointForUnit(name, ruleUnitDescr.getSimpleName()));
     }
 
-    public Optional<DeclarationSpec> getOOPathDeclarationById(String id) {
+    public Optional<TypedDeclarationSpec> getOOPathDeclarationById(String id) {
         return ooPathDeclarations.stream().filter(d -> d.getBindingId().equals(id)).findFirst();
     }
 
@@ -329,24 +367,28 @@ public class RuleContext {
         if (varType != null) {
             return varType;
         }
-        DeclarationSpec decl = scopedDeclarations.get( "$p" );
-        return decl != null ? decl.getDeclarationClass() : null;
+        DeclarationSpec decl = scopedDeclarations.get("$p" );
+        return decl instanceof TypedDeclarationSpec tDecl ? tDecl.getDeclarationClass() : null;
     }
 
-    public DeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass) {
-        return addDeclaration(new DeclarationSpec(defineVar(bindingId), declarationClass));
+    public TypedDeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass) {
+        return addDeclaration(new TypedDeclarationSpec(defineVar(bindingId), declarationClass));
     }
 
-    public DeclarationSpec addDeclaration( String bindingId, Class<?> declarationClass, Optional<PatternDescr> pattern, Optional<Expression> declarationSource) {
-        return addDeclaration(new DeclarationSpec(defineVar(bindingId), declarationClass, pattern, declarationSource, Optional.empty(), false));
+    public TypedDeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass, Optional<PatternDescr> pattern, Optional<Expression> declarationSource) {
+        return addDeclaration(new TypedDeclarationSpec(defineVar(bindingId), declarationClass, pattern, declarationSource, Optional.empty(), false));
     }
 
-    public DeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass, String variableName) {
-        return addDeclaration(new DeclarationSpec(defineVar(bindingId), declarationClass, variableName));
+    public TypedDeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass, String variableName) {
+        return addDeclaration(new TypedDeclarationSpec(defineVar(bindingId), declarationClass, variableName));
     }
 
-    public DeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass, Expression declarationSource) {
-        return addDeclaration(new DeclarationSpec(defineVar(bindingId), declarationClass, declarationSource));
+    public TypedDeclarationSpec addDeclaration(String bindingId, Class<?> declarationClass, Expression declarationSource) {
+        return addDeclaration(new TypedDeclarationSpec(defineVar(bindingId), declarationClass, declarationSource));
+    }
+
+    public PrototypeDeclarationSpec addPrototypeDeclaration(String bindingId, String prototypeType) {
+        return addDeclaration(new PrototypeDeclarationSpec(defineVar(bindingId), prototypeType, false));
     }
 
     private String defineVar(String var) {
@@ -360,15 +402,15 @@ public class RuleContext {
         return currentScope.id;
     }
 
-    public DeclarationSpec addDeclaration(DeclarationSpec d) {
+    public <T extends DeclarationSpec> T addDeclaration(T d) {
         this.scopedDeclarations.putIfAbsent( d.getBindingId(), d );
         this.allDeclarations.putIfAbsent( d.getBindingId(), d );
         return d;
     }
 
-    public void addDeclarationReplacing(DeclarationSpec d) {
+    public void addDeclarationReplacing(TypedDeclarationSpec d) {
         final String bindingId = d.getBindingId();
-        final Optional<DeclarationSpec> declarationById = getDeclarationById(bindingId);
+        final Optional<TypedDeclarationSpec> declarationById = getTypedDeclarationById(bindingId);
         if (declarationById.isPresent()) {
             removeDeclarationById(bindingId);
         }
@@ -387,7 +429,7 @@ public class RuleContext {
         }
     }
 
-    public void addOOPathDeclaration(DeclarationSpec d) {
+    public void addOOPathDeclaration(TypedDeclarationSpec d) {
         if(getOOPathDeclarationById(d.getBindingId()).isEmpty()) {
             this.ooPathDeclarations.add(d);
         }
@@ -401,7 +443,7 @@ public class RuleContext {
         return scopedDeclarations.keySet();
     }
 
-    public List<DeclarationSpec> getOOPathDeclarations() {
+    public List<TypedDeclarationSpec> getOOPathDeclarations() {
         return ooPathDeclarations;
     }
 
@@ -480,6 +522,10 @@ public class RuleContext {
         return ruleDialect;
     }
 
+    public boolean arePrototypesAllowed() {
+        return packageModel.arePrototypesAllowed();
+    }
+
     public void setRuleDialect(RuleDialect ruleDialect) {
         this.ruleDialect = ruleDialect;
     }
@@ -689,14 +735,9 @@ public class RuleContext {
         }
     }
 
-    public void setDialectFromAttributes(Collection<AttributeDescr> attributes) {
-        for (AttributeDescr a : attributes) {
-            if (a.getName().equals("dialect")) {
-                if (a.getValue().equals("mvel")) {
-                    setRuleDialect(RuleDialect.MVEL);
-                }
-                return;
-            }
+    public void setDialectFromAttribute(AttributeDescr attribute) {
+        if (attribute != null) {
+            setRuleDialect(RuleDialect.resolveDialect(attribute.getValue()));
         }
     }
 
@@ -709,7 +750,7 @@ public class RuleContext {
     }
 
     public Type getDelarationType(String variableName) {
-        return getDeclarationById(variableName).map(DeclarationSpec::getBoxedType)
+        return getTypedDeclarationById(variableName).map(TypedDeclarationSpec::getBoxedType)
                                                .orElseGet(UnknownType::new);
     }
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/TypedDeclarationSpec.java
similarity index 52%
copy from drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java
copy to drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/TypedDeclarationSpec.java
index f8d01f49b1..fc75419cee 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DeclarationSpec.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/TypedDeclarationSpec.java
@@ -24,19 +24,39 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.ClassExpr;
 import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
 import org.drools.base.base.ClassObjectType;
 import org.drools.base.rule.Declaration;
 import org.drools.base.rule.accessor.PatternExtractor;
+import org.drools.base.time.TimeUtils;
+import org.drools.core.rule.BehaviorRuntime;
 import org.drools.drl.ast.descr.BehaviorDescr;
 import org.drools.drl.ast.descr.EntryPointDescr;
 import org.drools.drl.ast.descr.PatternDescr;
+import org.drools.model.Variable;
+import org.drools.model.codegen.execmodel.PackageModel;
+import org.drools.model.codegen.execmodel.errors.UnknownDeclarationError;
 
+import static org.drools.model.codegen.execmodel.PackageModel.DOMAIN_CLASSESS_METADATA_FILE_NAME;
+import static org.drools.model.codegen.execmodel.PackageModel.DOMAIN_CLASS_METADATA_INSTANCE;
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.classToReferenceType;
 import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toStringLiteral;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.DECLARATION_OF_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.ENTRY_POINT_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.WINDOW_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createDslTopLevelMethod;
+import static org.drools.modelcompiler.util.ClassUtil.asJavaSourceName;
 import static org.drools.util.ClassUtils.rawType;
 
-public class DeclarationSpec {
+public class TypedDeclarationSpec implements DeclarationSpec {
     private final String bindingId;
     private final Type declarationType;
     private final Optional<PatternDescr> optPattern;
@@ -49,23 +69,23 @@ public class DeclarationSpec {
     private boolean boxed = false;
     private Optional<PatternDescr> belongingPatternDescr = Optional.empty();
 
-    public DeclarationSpec(String bindingId, Type declarationType) {
+    public TypedDeclarationSpec(String bindingId, Type declarationType) {
         this(bindingId, declarationType, Optional.empty(), Optional.empty(), Optional.empty(), false);
     }
 
-    public DeclarationSpec(String bindingId, Type declarationType, boolean isGlobal) {
+    public TypedDeclarationSpec(String bindingId, Type declarationType, boolean isGlobal) {
         this(bindingId, declarationType, Optional.empty(), Optional.empty(), Optional.empty(), isGlobal);
     }
 
-    DeclarationSpec(String bindingId, Type declarationType, String variableName) {
+    TypedDeclarationSpec(String bindingId, Type declarationType, String variableName) {
         this(bindingId, declarationType, Optional.empty(), Optional.empty(), Optional.of(variableName), false);
     }
 
-    DeclarationSpec(String bindingId, Type declarationType, Expression declarationSource) {
+    TypedDeclarationSpec(String bindingId, Type declarationType, Expression declarationSource) {
         this(bindingId, declarationType, Optional.empty(), Optional.of(declarationSource), Optional.empty(), false);
     }
 
-    DeclarationSpec(String bindingId, Type declarationType, Optional<PatternDescr> pattern, Optional<Expression> declarationSource, Optional<String> variableName, boolean isGlobal) {
+    TypedDeclarationSpec(String bindingId, Type declarationType, Optional<PatternDescr> pattern, Optional<Expression> declarationSource, Optional<String> variableName, boolean isGlobal) {
         this.bindingId = bindingId;
         this.declarationType = declarationType;
         this.optPattern = pattern;
@@ -85,10 +105,12 @@ public class DeclarationSpec {
         return optPattern.map(PatternDescr::getBehaviors).orElse(Collections.emptyList());
     }
 
+    @Override
     public String getBindingId() {
         return bindingId;
     }
 
+    @Override
     public Class<?> getDeclarationClass() {
         return rawType( declarationType );
     }
@@ -105,6 +127,7 @@ public class DeclarationSpec {
         return declarationSource;
     }
 
+    @Override
     public Optional<String> getVariableName() {
         return variableName;
     }
@@ -117,6 +140,7 @@ public class DeclarationSpec {
         return toClassOrInterfaceType(getDeclarationClass());
     }
 
+    @Override
     public boolean isGlobal() {
         return isGlobal;
     }
@@ -129,10 +153,12 @@ public class DeclarationSpec {
         this.boundVariable = boundVariable;
     }
 
+    @Override
     public MethodCallExpr getBindingExpr() {
         return bindingExpr;
     }
 
+    @Override
     public void setBindingExpr( MethodCallExpr bindingExpr ) {
         this.bindingExpr = bindingExpr;
     }
@@ -170,4 +196,58 @@ public class DeclarationSpec {
         this.belongingPatternDescr = belongingPatternDescr;
     }
 
+    @Override
+    public void registerOnPackage(PackageModel packageModel, RuleContext context, BlockStmt ruleBlock) {
+        boolean domainClass = packageModel.registerDomainClass( getDeclarationClass() );
+        if (!context.getGlobals().containsKey(getBindingId()) && context.getQueryParameterByName(getBindingId()).isEmpty()) {
+            addVariable(ruleBlock, context, domainClass);
+        }
+    }
+
+    private void addVariable(BlockStmt ruleBlock, RuleContext context, boolean domainClass) {
+        if (getDeclarationClass() == null) {
+            context.addCompilationError( new UnknownDeclarationError( getBindingId() ) );
+            return;
+        }
+
+        MethodCallExpr declarationOfCall = createDslTopLevelMethod(DECLARATION_OF_CALL);
+        declarationOfCall.addArgument(new ClassExpr(getBoxedType() ));
+
+        if (domainClass) {
+            String domainClassSourceName = asJavaSourceName( getDeclarationClass() );
+            declarationOfCall.addArgument( DOMAIN_CLASSESS_METADATA_FILE_NAME + context.getPackageModel().getPackageUUID() + "." + domainClassSourceName + DOMAIN_CLASS_METADATA_INSTANCE );
+        }
+
+        declarationOfCall.addArgument(toStringLiteral(getVariableName().orElse(getBindingId())));
+
+        getDeclarationSource().ifPresent(declarationOfCall::addArgument);
+
+        getEntryPoint().ifPresent( ep -> {
+            MethodCallExpr entryPointCall = createDslTopLevelMethod(ENTRY_POINT_CALL);
+            entryPointCall.addArgument( toStringLiteral(ep ) );
+            declarationOfCall.addArgument( entryPointCall );
+        } );
+
+        for ( BehaviorDescr behaviorDescr : getBehaviors() ) {
+            MethodCallExpr windowCall = createDslTopLevelMethod(WINDOW_CALL);
+            if ( BehaviorRuntime.BehaviorType.TIME_WINDOW.matches(behaviorDescr.getSubType()) ) {
+                windowCall.addArgument( "org.drools.model.Window.Type.TIME" );
+                windowCall.addArgument( "" + TimeUtils.parseTimeString(behaviorDescr.getParameters().get(0 ) ) );
+            }
+            if ( BehaviorRuntime.BehaviorType.LENGTH_WINDOW.matches(behaviorDescr.getSubType()) ) {
+                windowCall.addArgument( "org.drools.model.Window.Type.LENGTH" );
+                windowCall.addArgument( "" + Integer.valueOf( behaviorDescr.getParameters().get( 0 ) ) );
+            }
+            declarationOfCall.addArgument( windowCall );
+        }
+
+        ClassOrInterfaceType varType = toClassOrInterfaceType(Variable.class);
+        varType.setTypeArguments( classToReferenceType(this) );
+        VariableDeclarationExpr varExpr = new VariableDeclarationExpr(varType, context.getVar(getBindingId()), Modifier.finalModifier());
+
+        AssignExpr varAssign = new AssignExpr(varExpr, declarationOfCall, AssignExpr.Operator.ASSIGN);
+        if (!DrlxParseUtil.hasDuplicateExpr(ruleBlock, varAssign)) {
+            ruleBlock.addStatement(varAssign);
+        }
+    }
 }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintExpression.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintExpression.java
index 0563c0340c..08c4786c82 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintExpression.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintExpression.java
@@ -67,7 +67,7 @@ public class ConstraintExpression {
     private static String parseConstraintExpression( RuleContext context, Class<?> patternType, BaseDescr constraint, boolean isPositional ) {
         if (isPositional) {
             String expr = constraint.toString();
-            boolean isConstraint = !isIdentifier(expr) || context.getDeclarationById( expr ).isPresent();
+            boolean isConstraint = !isIdentifier(expr) || context.getTypedDeclarationById(expr ).isPresent();
             int position = ((ExprConstraintDescr ) constraint).getPosition();
             Optional<String> field = getFieldAtPosition(context, patternType, position);
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
index 36b8f67a29..8702e687c9 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java
@@ -53,7 +53,7 @@ import org.drools.model.Index;
 import org.drools.model.codegen.execmodel.PackageModel;
 import org.drools.model.codegen.execmodel.errors.ParseExpressionErrorResult;
 import org.drools.model.codegen.execmodel.errors.VariableUsedInBindingError;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.ModelGenerator;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
@@ -200,7 +200,7 @@ public class ConstraintParser {
     }
 
     private void addDeclaration(DrlxExpression drlx, SingleDrlxParseSuccess singleResult, String bindId) {
-        DeclarationSpec decl = context.addDeclaration(bindId, getDeclarationType(drlx, singleResult));
+        TypedDeclarationSpec decl = context.addDeclaration(bindId, getDeclarationType(drlx, singleResult));
         if (drlx.getExpr() instanceof NameExpr) {
             decl.setBoundVariable( PrintUtil.printNode(drlx.getExpr()) );
         } else if (drlx.getExpr() instanceof BinaryExpr) {
@@ -505,7 +505,7 @@ public class ConstraintParser {
                     .setLeft( new TypedExpression( withThis, converted.getType() ) )
                     .addReactOnProperty( lcFirstForBean(nameExpr.getNameAsString()) );
         } else if (context.hasDeclaration( expression )) {
-            Optional<DeclarationSpec> declarationSpec = context.getDeclarationById(expression);
+            Optional<TypedDeclarationSpec> declarationSpec = context.getTypedDeclarationById(expression);
             if (declarationSpec.isPresent()) {
                 return new SingleDrlxParseSuccess(patternType, bindingId, context.getVarExpr(printNode(drlxExpr)), declarationSpec.get().getDeclarationClass() ).setIsPredicate(true);
             } else {
@@ -800,10 +800,10 @@ public class ConstraintParser {
     private boolean hasDeclarationFromOtherPattern(ExpressionTyperContext expressionTyperContext) {
         return expressionTyperContext.getUsedDeclarations()
                                      .stream()
-                                     .map(context::getDeclarationById)
+                                     .map(context::getTypedDeclarationById)
                                      .anyMatch(optDecl -> {
                                          if (optDecl.isPresent()) {
-                                             DeclarationSpec decl = optDecl.get();
+                                             TypedDeclarationSpec decl = optDecl.get();
                                              if (!decl.isGlobal() && decl.getBelongingPatternDescr() != context.getCurrentPatternDescr()) {
                                                  return true;
                                              }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
index 0bd0ebcb8a..8c071c0d43 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expression/AbstractExpressionBuilder.java
@@ -184,7 +184,7 @@ public abstract class AbstractExpressionBuilder {
             return false;
         }
         return usedDeclarations.stream()
-                .map( context::getDeclarationById )
+                .map( context::getTypedDeclarationById)
                 .noneMatch(optDecl -> optDecl.isPresent() && optDecl.get().isGlobal() );
     }
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
index 8fdfb696c4..2aad35aba3 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
@@ -65,7 +65,7 @@ import com.github.javaparser.ast.type.ReferenceType;
 import com.github.javaparser.ast.type.Type;
 import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
 import org.drools.model.codegen.execmodel.errors.ParseExpressionErrorResult;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.ModelGenerator;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
@@ -450,7 +450,7 @@ public class ExpressionTyper {
             return of(new TypedExpression(plusThis, expression.getType(), name));
         }
 
-        Optional<DeclarationSpec> decl = ruleContext.getDeclarationById(name);
+        Optional<TypedDeclarationSpec> decl = ruleContext.getTypedDeclarationById(name);
         if (decl.isPresent()) {
             // then drlxExpr is a single NameExpr referring to a binding, e.g.: "$p1".
             context.addUsedDeclarations(name);
@@ -535,7 +535,7 @@ public class ExpressionTyper {
 
         if (originalTypeCursor != null && originalTypeCursor.equals(Object.class)) {
             // try infer type  from the declarations
-            final Optional<DeclarationSpec> declarationById = ruleContext.getDeclarationById(printNode(firstChild));
+            final Optional<TypedDeclarationSpec> declarationById = ruleContext.getTypedDeclarationById(printNode(firstChild));
             originalTypeCursor = declarationById.map(d -> (java.lang.reflect.Type)d.getDeclarationClass()).orElse(originalTypeCursor);
         }
 
@@ -641,7 +641,7 @@ public class ExpressionTyper {
             }
         } else if (arg instanceof NameExpr) {
             String name = ((NameExpr) arg).getNameAsString();
-            ruleContext.getDeclarationById(name)
+            ruleContext.getTypedDeclarationById(name)
                        .filter(decl -> decl.getBelongingPatternDescr().isPresent())
                        .filter(decl -> {
                            if (decl.getBelongingPatternDescr().equals(ruleContext.getCurrentPatternDescr())) {
@@ -713,7 +713,7 @@ public class ExpressionTyper {
 
         } else if (firstNode instanceof MethodCallExpr) {
             Optional<Expression> scopeExpr = ((MethodCallExpr) firstNode).getScope();
-            Optional<DeclarationSpec> scopeDecl = scopeExpr.flatMap( scope -> ruleContext.getDeclarationById(PrintUtil.printNode(scope) ) );
+            Optional<TypedDeclarationSpec> scopeDecl = scopeExpr.flatMap(scope -> ruleContext.getTypedDeclarationById(PrintUtil.printNode(scope) ) );
 
             Expression scope;
             java.lang.reflect.Type type;
@@ -751,7 +751,7 @@ public class ExpressionTyper {
             result = of( binaryExpr( ( BinaryExpr ) firstNode ));
 
         } else if (firstNode instanceof ArrayAccessExpr) {
-            Optional<DeclarationSpec> scopeDecl = ruleContext.getDeclarationById( ((ArrayAccessExpr) firstNode).getName().toString() );
+            Optional<TypedDeclarationSpec> scopeDecl = ruleContext.getTypedDeclarationById(((ArrayAccessExpr) firstNode).getName().toString() );
 
             Expression scope;
             java.lang.reflect.Type type;
@@ -1127,10 +1127,10 @@ public class ExpressionTyper {
 
         // In OOPath a declaration is based on a position rather than a name.
         // Only an OOPath chunk can have a backreference expression
-        Optional<DeclarationSpec> backReference = empty();
+        Optional<TypedDeclarationSpec> backReference = empty();
         if ( firstNode.getBackReferencesCount() > 0) {
-            List<DeclarationSpec> ooPathDeclarations = ruleContext.getOOPathDeclarations();
-            DeclarationSpec backReferenceDeclaration = ooPathDeclarations.get(ooPathDeclarations.size() - 1 - firstNode.getBackReferencesCount());
+            List<TypedDeclarationSpec> ooPathDeclarations = ruleContext.getOOPathDeclarations();
+            TypedDeclarationSpec backReferenceDeclaration = ooPathDeclarations.get(ooPathDeclarations.size() - 1 - firstNode.getBackReferencesCount());
             typeCursor = backReferenceDeclaration.getDeclarationClass();
             backReference = of(backReferenceDeclaration);
             context.addUsedDeclarations(backReferenceDeclaration.getBindingId());
@@ -1181,7 +1181,7 @@ public class ExpressionTyper {
             }
         }
 
-        Optional<DeclarationSpec> declarationById = ruleContext.getDeclarationById(firstName);
+        Optional<TypedDeclarationSpec> declarationById = ruleContext.getTypedDeclarationById(firstName);
         if (declarationById.isPresent()) {
             // do NOT append any reactOnProperties.
             // because reactOnProperties is referring only to the properties of the type of the pattern, not other declarations properites.
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/FromVisitor.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/FromVisitor.java
index 0e04eacedd..56ac90e42f 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/FromVisitor.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/FromVisitor.java
@@ -37,7 +37,7 @@ import com.github.javaparser.ast.stmt.ExpressionStmt;
 import org.drools.drl.ast.descr.FromDescr;
 import org.drools.drl.ast.descr.PatternSourceDescr;
 import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
 import org.drools.model.codegen.execmodel.generator.TypedExpression;
@@ -121,7 +121,7 @@ public class FromVisitor {
             if (isEnumeratedList( expr )) {
                 asListCall.addArgument( createListForLiteralFrom( expr.substring( 1, expr.length()-1 ), fromCall, usedDeclarations ) );
             } else {
-                Optional<DeclarationSpec> optContainsBinding = context.getDeclarationById( expr );
+                Optional<TypedDeclarationSpec> optContainsBinding = context.getTypedDeclarationById(expr );
                 if ( optContainsBinding.isPresent() ) {
                     String bindingId = optContainsBinding.get().getBindingId();
                     fromCall.addArgument( context.getVarExpr( bindingId ) );
@@ -269,7 +269,7 @@ public class FromVisitor {
 
     private Expression createArg(String expression, String bindingId, MethodCallExpr fromCall) {
         if (bindingId != null) {
-            DeclarationSpec declarationSpec = context.getDeclarationById( bindingId ).orElseThrow( RuntimeException::new );
+            TypedDeclarationSpec declarationSpec = context.getTypedDeclarationById(bindingId ).orElseThrow(RuntimeException::new );
             Class<?> clazz = declarationSpec.getDeclarationClass();
 
             DrlxParseResult drlxParseResult = ConstraintParser.withoutVariableValidationConstraintParser(context, context.getPackageModel())
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateInline.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateInline.java
index 2034e4220c..d6a111d1ca 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateInline.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateInline.java
@@ -55,7 +55,7 @@ import org.drools.drl.ast.descr.FromDescr;
 import org.drools.drl.ast.descr.PatternDescr;
 import org.drools.drl.ast.descr.PatternSourceDescr;
 import org.drools.model.codegen.execmodel.PackageModel;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
 import org.drools.modelcompiler.util.StringUtil;
@@ -86,7 +86,7 @@ public class AccumulateInline {
     private ClassOrInterfaceDeclaration contextData;
     private String accumulateInlineClassName;
 
-    private final List<DeclarationSpec> accumulateDeclarations = new ArrayList<>();
+    private final List<TypedDeclarationSpec> accumulateDeclarations = new ArrayList<>();
     private final List<String> contextFieldNames = new ArrayList<>();
     private Set<String> usedExternalDeclarations = new HashSet<>();
     private Type singleAccumulateType;
@@ -130,7 +130,7 @@ public class AccumulateInline {
             throw new UnsupportedInlineAccumulate();
         }
 
-        for (DeclarationSpec d : accumulateDeclarations) {
+        for (TypedDeclarationSpec d : accumulateDeclarations) {
             context.addDeclaration(d);
         }
 
@@ -202,7 +202,7 @@ public class AccumulateInline {
                         initMethodBody.addStatement(initStmt);
                         initStmt.findAll(NameExpr.class).stream().map(Node::toString).filter(context::hasDeclaration).forEach(usedExternalDeclarations::add);
                     });
-                    accumulateDeclarations.add(new DeclarationSpec(variableName, DrlxParseUtil.getClassFromContext(context.getTypeResolver(), vd.getType().asString())));
+                    accumulateDeclarations.add(new TypedDeclarationSpec(variableName, DrlxParseUtil.getClassFromContext(context.getTypeResolver(), vd.getType().asString())));
                 }
             }
         }
@@ -237,7 +237,7 @@ public class AccumulateInline {
             String nameExpr = allNamesInActionBlock.iterator().next();
             accumulateMethod.getParameter(1).setName(nameExpr);
             singleAccumulateType =
-                    context.getDeclarationById(nameExpr)
+                    context.getTypedDeclarationById(nameExpr)
                             .orElseThrow(() -> new IllegalStateException("Cannot find declaration by name " + nameExpr + "!"))
                             .getBoxedType();
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateVisitor.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateVisitor.java
index 7b202abedb..773bcc19a3 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateVisitor.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/AccumulateVisitor.java
@@ -18,6 +18,15 @@
  */
 package org.drools.model.codegen.execmodel.generator.visitor.accumulate;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
 import com.github.javaparser.ast.Node;
 import com.github.javaparser.ast.NodeList;
 import com.github.javaparser.ast.body.Parameter;
@@ -29,7 +38,6 @@ import com.github.javaparser.ast.expr.MethodCallExpr;
 import com.github.javaparser.ast.expr.MethodReferenceExpr;
 import com.github.javaparser.ast.expr.NameExpr;
 import com.github.javaparser.ast.expr.ObjectCreationExpr;
-import com.github.javaparser.ast.expr.StringLiteralExpr;
 import com.github.javaparser.ast.stmt.BlockStmt;
 import com.github.javaparser.ast.stmt.ExpressionStmt;
 import com.github.javaparser.ast.type.ClassOrInterfaceType;
@@ -47,6 +55,7 @@ import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
 import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.TypedExpression;
 import org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser;
 import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseFail;
@@ -65,15 +74,6 @@ import org.drools.mvel.parser.ast.expr.DrlNameExpr;
 import org.kie.api.runtime.rule.AccumulateFunction;
 import org.kie.internal.builder.conf.AccumulateFunctionOption;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-
 import static java.util.Optional.ofNullable;
 import static java.util.stream.Collectors.toList;
 import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getLiteralExpressionType;
@@ -237,7 +237,7 @@ public class AccumulateVisitor {
 
     private void nameExprParameter(PatternDescr basePattern, AccumulateDescr.AccumulateFunctionCallDescr function, MethodCallExpr functionDSL, String bindingId, Expression accumulateFunctionParameter) {
         String nameExpr = ((DrlNameExpr) accumulateFunctionParameter).getName().asString();
-        Optional<DeclarationSpec> declaration = context.getDeclarationById(nameExpr);
+        Optional<DeclarationSpec> declaration = context.getTypedDeclarationById(nameExpr).map(DeclarationSpec.class::cast);
         if (declaration.isEmpty()) {
             String name = nameExpr;
             declaration = context.getAllDeclarations().stream().filter( d -> d.getVariableName().map( n -> n.equals( name ) ).orElse( false ) ).findFirst();
@@ -271,9 +271,9 @@ public class AccumulateVisitor {
         final DrlxParseUtil.RemoveRootNodeResult methodCallWithoutRootNode = DrlxParseUtil.removeRootNode(parameterConverted);
 
         String rootNodeName = getRootNodeName(methodCallWithoutRootNode);
-        Optional<DeclarationSpec> decl = context.getDeclarationById(rootNodeName);
+        Optional<TypedDeclarationSpec> decl = context.getTypedDeclarationById(rootNodeName);
 
-        Class<?> clazz = decl.map(DeclarationSpec::getDeclarationClass)
+        Class<?> clazz = decl.map(TypedDeclarationSpec::getDeclarationClass)
                 .orElseGet( () -> {
                     try {
                         return context.getTypeResolver().resolveType(rootNodeName);
@@ -307,7 +307,7 @@ public class AccumulateVisitor {
         PatternDescr inputPattern = decl.isPresent() ? null : findInputPattern(input);
         if (inputPattern != null) {
             String inputId = inputPattern.getIdentifier();
-            Optional<DeclarationSpec> accumulateClassDeclOpt = context.getDeclarationById(inputId);
+            Optional<TypedDeclarationSpec> accumulateClassDeclOpt = context.getTypedDeclarationById(inputId);
             if (accumulateClassDeclOpt.isPresent()) {
                 // when static method is used in accumulate function, "_this" is a pattern input
                 // Note that DrlxParseUtil.generateLambdaWithoutParameters() takes the patternType as a class of "_this"
@@ -364,10 +364,10 @@ public class AccumulateVisitor {
             SingleDrlxParseSuccess singleResult = drlxParseResult;
             singleResult.setExprBinding(bindExpressionVariable);
             final MethodCallExpr binding = expressionBuilder.buildBinding(singleResult);
-            context.addDeclarationReplacing(new DeclarationSpec(bindExpressionVariable, methodCallExprType));
+            context.addDeclarationReplacing(new TypedDeclarationSpec(bindExpressionVariable, methodCallExprType));
             functionDSL.addArgument(context.getVarExpr(bindExpressionVariable));
 
-            context.addDeclarationReplacing(new DeclarationSpec(bindingId, accumulateFunctionResultType));
+            context.addDeclarationReplacing(new TypedDeclarationSpec(bindingId, accumulateFunctionResultType));
 
             context.getExpressions().forEach(expression -> replaceTypeInExprLambdaAndIndex(bindingId, accumulateFunctionResultType, expression));
 
@@ -421,12 +421,12 @@ public class AccumulateVisitor {
 
                 singleResult.setExprBinding(bindExpressionVariable);
 
-                context.addDeclarationReplacing(new DeclarationSpec(singleResult.getPatternBinding(), exprRawClass));
+                context.addDeclarationReplacing(new TypedDeclarationSpec(singleResult.getPatternBinding(), exprRawClass));
                 context.getExpressions().forEach(expression -> replaceTypeInExprLambdaAndIndex(bindingId, exprRawClass, expression));
 
                 functionDSL.addArgument(createAccSupplierExpr(accumulateFunction));
                 final MethodCallExpr newBindingFromBinary = AccumulateVisitor.this.buildBinding(bindExpressionVariable, singleResult.getUsedDeclarations(), singleResult.getExpr());
-                context.addDeclarationReplacing(new DeclarationSpec(bindExpressionVariable, exprRawClass));
+                context.addDeclarationReplacing(new TypedDeclarationSpec(bindExpressionVariable, exprRawClass));
                 functionDSL.addArgument(context.getVarExpr(bindExpressionVariable));
                 return Optional.of(new NewBinding(Collections.emptyList(), newBindingFromBinary));
             }
@@ -443,7 +443,7 @@ public class AccumulateVisitor {
         validateAccFunctionTypeAgainstPatternType(context, basePattern, accumulateFunction);
         functionDSL.addArgument(createAccSupplierExpr(accumulateFunction));
         Class accumulateFunctionResultType = accumulateFunction.getResultType();
-        context.addDeclarationReplacing(new DeclarationSpec(bindingId, accumulateFunctionResultType));
+        context.addDeclarationReplacing(new TypedDeclarationSpec(bindingId, accumulateFunctionResultType));
         context.getExpressions().forEach(expression -> replaceTypeInExprLambdaAndIndex(bindingId, accumulateFunctionResultType, expression));
     }
 
@@ -485,7 +485,7 @@ public class AccumulateVisitor {
 
     private void addBindingAsDeclaration(RuleContext context, String bindingId, Class accumulateFunctionResultType) {
         if (bindingId != null) {
-            context.addDeclarationReplacing(new DeclarationSpec(bindingId, accumulateFunctionResultType));
+            context.addDeclarationReplacing(new TypedDeclarationSpec(bindingId, accumulateFunctionResultType));
             if (context.getExpressions().size() > 1) {
                 // replace the type of the lambda with the one resulting from the accumulate operation only in the pattern immediately before it
                 replaceTypeInExprLambdaAndIndex(bindingId, accumulateFunctionResultType, context.getExpressions().get(context.getExpressions().size()-2));
@@ -530,7 +530,7 @@ public class AccumulateVisitor {
 
     static List<String> collectNamesInBlock(BlockStmt block, RuleContext context) {
         return block.findAll(NameExpr.class, n -> {
-            Optional<DeclarationSpec> optD = context.getDeclarationById(n.getNameAsString());
+            Optional<TypedDeclarationSpec> optD = context.getTypedDeclarationById(n.getNameAsString());
             return optD.filter(d -> !d.isGlobal()).isPresent(); // Global aren't supported
         })
                 .stream()
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/GroupByVisitor.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/GroupByVisitor.java
index c093a232fa..67e0392e89 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/GroupByVisitor.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/GroupByVisitor.java
@@ -26,7 +26,7 @@ import org.drools.drl.ast.descr.GroupByDescr;
 import org.drools.drl.ast.descr.PatternDescr;
 import org.drools.model.codegen.execmodel.PackageModel;
 import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
 import org.drools.model.codegen.execmodel.generator.TypedExpression;
 import org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper;
@@ -65,7 +65,7 @@ public class GroupByVisitor extends AccumulateVisitor {
         TypedExpression typedExpression = optResult.get();
 
         String groupingKey = groupByDescr.getGroupingKey() != null ? groupByDescr.getGroupingKey() : generateUUID();
-        context.addDeclarationReplacing(new DeclarationSpec(groupingKey, typedExpression.getRawClass()));
+        context.addDeclarationReplacing(new TypedDeclarationSpec(groupingKey, typedExpression.getRawClass()));
 
         accumulateDSL.addArgument(toVar(groupingKey));
 
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/LegacyAccumulate.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/LegacyAccumulate.java
index 212d1c0f70..94ebb85469 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/LegacyAccumulate.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/accumulate/LegacyAccumulate.java
@@ -230,7 +230,7 @@ public class LegacyAccumulate {
         public Map<String, Declaration> getDeclarations( RuleImpl rule ) {
             Map<String, Declaration> declarationMap = new HashMap<>();
             for (String externalDeclr : externalDeclrs) {
-                context.getDeclarationById( externalDeclr ).ifPresent( dSpec -> declarationMap.put(externalDeclr, dSpec.asDeclaration()) );
+                context.getTypedDeclarationById(externalDeclr ).ifPresent(dSpec -> declarationMap.put(externalDeclr, dSpec.asDeclaration()) );
             }
             declarationMap.putAll( delegate.getDeclarations( rule ) );
             return declarationMap;
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ClassPatternDSL.java
similarity index 72%
copy from drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java
copy to drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ClassPatternDSL.java
index 6e1ec9d698..31ef46b782 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ClassPatternDSL.java
@@ -18,13 +18,21 @@
  */
 package org.drools.model.codegen.execmodel.generator.visitor.pattern;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
 import org.drools.base.util.PropertyReactivityUtil;
 import org.drools.compiler.compiler.DescrBuildError;
-import org.drools.drl.ast.descr.AccumulateDescr;
 import org.drools.drl.ast.descr.BaseDescr;
-import org.drools.drl.ast.descr.ExprConstraintDescr;
 import org.drools.drl.ast.descr.PatternDescr;
 import org.drools.drl.ast.descr.PatternSourceDescr;
 import org.drools.model.codegen.execmodel.PackageModel;
@@ -34,6 +42,7 @@ import org.drools.model.codegen.execmodel.generator.ConstraintUtil;
 import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
+import org.drools.model.codegen.execmodel.generator.TypedDeclarationSpec;
 import org.drools.model.codegen.execmodel.generator.WindowReferenceGenerator;
 import org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintExpression;
 import org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser;
@@ -47,51 +56,91 @@ import org.drools.model.codegen.execmodel.generator.visitor.DSLNode;
 import org.drools.model.codegen.execmodel.generator.visitor.FromVisitor;
 import org.kie.api.definition.rule.Watch;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 import static org.drools.compiler.rule.builder.PatternBuilder.lookAheadFieldsOfIdentifier;
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.findLastMethodInChain;
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.findRootNodeViaScope;
 import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getPatternListenedProperties;
-import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.validateDuplicateBindings;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.NO_OP_EXPR;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PASSIVE_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PATTERN_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.WATCH_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createDslTopLevelMethod;
 import static org.drools.model.impl.NamesGenerator.generateName;
 import static org.drools.model.impl.VariableImpl.GENERATED_VARIABLE_PREFIX;
 import static org.drools.mvel.parser.printer.PrintUtil.printNode;
 import static org.drools.util.StreamUtils.optionalToStream;
 
-public abstract class PatternDSL implements DSLNode {
+public class ClassPatternDSL extends PatternDSL {
 
-    protected final RuleContext context;
-    protected final PackageModel packageModel;
-    protected final PatternDescr pattern;
-    private final List<? extends BaseDescr> constraintDescrs;
-    protected Class<?> patternType;
+    private Class<?> patternType;
 
-    PatternDSL(RuleContext context, PackageModel packageModel, PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
-        this.context = context;
-        this.packageModel = packageModel;
-        this.pattern = pattern;
-        this.constraintDescrs = constraintDescrs;
+    ClassPatternDSL(RuleContext context, PackageModel packageModel, PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
+        super(context, packageModel, pattern, constraintDescrs);
         this.patternType = patternType;
     }
 
+    @Override
+    protected String getPatternTypeName() {
+        return patternType.getSimpleName();
+    }
+
+    @Override
+    protected Class<?> getPatternType() {
+        return patternType;
+    }
+
+    @Override
     public DeclarationSpec initPattern() {
         generatePatternIdentifierIfMissing();
         context.addPatternBinding(pattern.getIdentifier());
         final Optional<Expression> declarationSource = buildFromDeclaration(pattern);
-        return context.addDeclaration(pattern.getIdentifier(), patternType, Optional.of(pattern), declarationSource);
+        return context.addDeclaration(pattern.getIdentifier(), getPatternType(), Optional.of(pattern), declarationSource);
     }
 
-    private static boolean isPositional(BaseDescr constraint) {
-        return constraint instanceof ExprConstraintDescr &&
-                ((ExprConstraintDescr) constraint).getType() == ExprConstraintDescr.Type.POSITIONAL &&
-                !constraint.getText().contains( ":=" );
+    @Override
+    protected void buildPattern(DeclarationSpec declarationSpec, List<PatternConstraintParseResult> patternConstraintParseResults) {
+        MethodCallExpr patternExpression = createPatternExpression(pattern, (TypedDeclarationSpec) declarationSpec);
+
+        List<Expression> exprs = new ArrayList<>();
+        context.pushExprPointer(exprs::add);
+        buildConstraints(pattern, patternType, patternConstraintParseResults);
+        context.popExprPointer();
+
+        List<Expression> additionalPatterns = new ArrayList<>();
+        for (Expression expr : exprs) {
+            Optional<Expression> rootScope = findRootNodeViaScope(expr );
+            if ( rootScope.isPresent() && (( MethodCallExpr ) rootScope.get()).getNameAsString().equals( PATTERN_CALL ) ) {
+                additionalPatterns.add( expr );
+            } else {
+                MethodCallExpr currentExpr = ( MethodCallExpr ) expr;
+                MethodCallExpr lastMethodInChain = findLastMethodInChain(currentExpr);
+                if (!NO_OP_EXPR.equals(lastMethodInChain.getNameAsString())) {
+                    lastMethodInChain.setScope(patternExpression);
+                    patternExpression = currentExpr;
+                }
+            }
+        }
+
+        if (pattern.isQuery()) {
+            patternExpression = new MethodCallExpr( patternExpression, PASSIVE_CALL );
+        }
+
+        context.addExpression( addWatchToPattern( patternExpression ) );
+        additionalPatterns.forEach( context::addExpression );
+    }
+
+    protected void generatePatternIdentifierIfMissing() {
+        // the PatternDescr can be shared by multiple rules in case of rules inheritance, so its identifier has to
+        // be set atomically when rule generation is performed in parallel
+        synchronized (pattern) {
+            if (pattern.getIdentifier() == null) {
+                final String generatedName = generateName("pattern_" + getPatternTypeName());
+                final String patternNameAggregated = findFirstInnerBinding(constraintDescrs, patternType)
+                        .map(ib -> context.getAggregatePatternMap().putIfAbsent(new AggregateKey(ib, getPatternTypeName()), generatedName))
+                        .orElse(generatedName);
+                pattern.setIdentifier(GENERATED_VARIABLE_PREFIX + patternNameAggregated);
+            }
+        }
     }
 
     private Optional<Expression> buildFromDeclaration(PatternDescr pattern) {
@@ -108,20 +157,6 @@ public abstract class PatternDSL implements DSLNode {
         return source.flatMap(sourceDescr -> new WindowReferenceGenerator(packageModel, context.getTypeResolver()).visit(sourceDescr, context));
     }
 
-    private void generatePatternIdentifierIfMissing() {
-        // the PatternDescr can be shared by multiple rules in case of rules inheritance, so its identifier has to
-        // be set atomically when rule generation is performed in parallel
-        synchronized (pattern) {
-            if (pattern.getIdentifier() == null) {
-                final String generatedName = generateName("pattern_" + patternType.getSimpleName());
-                final String patternNameAggregated = findFirstInnerBinding(constraintDescrs, patternType)
-                        .map(ib -> context.getAggregatePatternMap().putIfAbsent(new AggregateKey(ib, patternType), generatedName))
-                        .orElse(generatedName);
-                pattern.setIdentifier(GENERATED_VARIABLE_PREFIX + patternNameAggregated);
-            }
-        }
-    }
-
     private Optional<String> findFirstInnerBinding(List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
         return constraintDescrs.stream()
                 .map( constraint -> ConstraintExpression.createConstraintExpression( context, patternType, constraint, isPositional(constraint) ).getExpression() )
@@ -131,7 +166,8 @@ public abstract class PatternDSL implements DSLNode {
                 .findFirst();
     }
 
-    private List<PatternConstraintParseResult> findAllConstraint(PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
+    @Override
+    protected List<PatternConstraintParseResult> findAllConstraint(PatternDescr pattern, List<? extends BaseDescr> constraintDescrs) {
         ConstraintParser constraintParser = ConstraintParser.defaultConstraintParser(context, packageModel);
         List<PatternConstraintParseResult> patternConstraintParseResults = new ArrayList<>();
 
@@ -181,7 +217,7 @@ public abstract class PatternDSL implements DSLNode {
 
     private void addImplicitCastExpr(ConstraintParser constraintParser, String patternIdentifier, List<PatternConstraintParseResult> patternConstraintParseResults) {
         final boolean hasInstanceOfExpr = patternConstraintParseResults.stream()
-                .anyMatch(r -> r.getDrlxParseResult().acceptWithReturnValue(new ParseResultVisitor<>() {
+                .anyMatch(r -> r.drlxParseResult().acceptWithReturnValue(new ParseResultVisitor<>() {
                     @Override
                     public Boolean onSuccess(DrlxParseSuccess t) {
                         Expression expr = t.getExpr();
@@ -196,7 +232,7 @@ public abstract class PatternDSL implements DSLNode {
 
         final Optional<Expression> implicitCastExpression =
                 patternConstraintParseResults.stream()
-                .flatMap(r -> optionalToStream(r.getDrlxParseResult().acceptWithReturnValue(new ParseResultVisitor<Optional<Expression>>() {
+                .flatMap(r -> optionalToStream(r.drlxParseResult().acceptWithReturnValue(new ParseResultVisitor<Optional<Expression>>() {
                     @Override
                     public Optional<Expression> onSuccess(DrlxParseSuccess t) {
                         return t.getImplicitCastExpression();
@@ -221,7 +257,7 @@ public abstract class PatternDSL implements DSLNode {
     private void addNullSafeExpr(ConstraintParser constraintParser, String patternIdentifier, List<PatternConstraintParseResult> patternConstraintParseResults) {
         final List<Expression> nullSafeExpressions =
                 patternConstraintParseResults.stream()
-                                             .flatMap(r -> r.getDrlxParseResult().acceptWithReturnValue(new ParseResultVisitor<List<Expression>>() {
+                                             .flatMap(r -> r.drlxParseResult().acceptWithReturnValue(new ParseResultVisitor<List<Expression>>() {
 
                                                  @Override
                                                  public List<Expression> onSuccess(DrlxParseSuccess t) {
@@ -252,8 +288,8 @@ public abstract class PatternDSL implements DSLNode {
         return newNullSafeExpressions;
     }
 
-    void buildConstraint(PatternDescr pattern, Class<?> patternType, PatternConstraintParseResult patternConstraintParseResult) {
-        DrlxParseResult drlxParseResult = patternConstraintParseResult.getDrlxParseResult();
+    private void buildConstraint(PatternDescr pattern, Class<?> patternType, PatternConstraintParseResult patternConstraintParseResult) {
+        DrlxParseResult drlxParseResult = patternConstraintParseResult.drlxParseResult();
 
         DrlxParseResult withBindingCheck = drlxParseResult.acceptWithReturnValue(new ParseResultVisitor<>() {
             @Override
@@ -300,34 +336,7 @@ public abstract class PatternDSL implements DSLNode {
         }
     }
 
-    @Override
-    public void buildPattern() {
-        try {
-            context.setCurrentPatternDescr(Optional.of(pattern));
-            DeclarationSpec declarationSpec = initPattern();
-
-            if (constraintDescrs.isEmpty() && !(pattern.getSource() instanceof AccumulateDescr)) {
-                context.addExpression(input(declarationSpec));
-            } else {
-                final List<PatternConstraintParseResult> patternConstraintParseResults = findAllConstraint(pattern, constraintDescrs, patternType);
-                final List<String> allBindings = patternConstraintParseResults
-                        .stream()
-                        .map(p -> p.getDrlxParseResult().acceptWithReturnValue( DrlxParseSuccess::getExprBinding ))
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList());
-
-                validateDuplicateBindings(context.getRuleName(), allBindings).ifPresent(context::addCompilationError);
-
-                if (!context.hasErrors()) {
-                    buildPattern(declarationSpec, patternConstraintParseResults);
-                }
-            }
-        } finally {
-            context.resetCurrentPatternDescr();
-        }
-    }
-
-    Set<String> getSettableWatchedProps() {
+    private Set<String> getSettableWatchedProps() {
         Set<String> settableWatchedProps = new HashSet<>();
         Collection<String> settableProps = PropertyReactivityUtil.getAccessibleProperties(patternType);
 
@@ -360,9 +369,54 @@ public abstract class PatternDSL implements DSLNode {
         }
     }
 
-    protected abstract void buildPattern(DeclarationSpec declarationSpec, List<PatternConstraintParseResult> patternConstraintParseResults);
+    @Override
+    protected MethodCallExpr input(DeclarationSpec declarationSpec) {
+        return addWatchToPattern( createPatternExpression(pattern, (TypedDeclarationSpec) declarationSpec) );
+    }
 
-    protected abstract MethodCallExpr input(DeclarationSpec declarationSpec);
+    private MethodCallExpr addWatchToPattern( MethodCallExpr patternExpression ) {
+        Set<String> settableWatchedProps = getSettableWatchedProps();
+        if ( !settableWatchedProps.isEmpty() ) {
+            if (context.isPropertyReactive(patternType)) {
+                patternExpression = new MethodCallExpr(patternExpression, WATCH_CALL);
+                settableWatchedProps.stream().map(StringLiteralExpr::new).forEach(patternExpression::addArgument);
+            } else {
+                context.addCompilationError(new InvalidExpressionErrorResult("Wrong usage of @" + Watch.class.getSimpleName() + " annotation on class " + patternType.getName() + " that is not annotated as @PropertyReactive"));
+            }
+        }
+        return patternExpression;
+    }
 
-    protected abstract DSLNode createSimpleConstraint( DrlxParseSuccess drlxParseResult, PatternDescr pattern );
+    private MethodCallExpr createPatternExpression(PatternDescr pattern, TypedDeclarationSpec declarationSpec) {
+        MethodCallExpr dslExpr = createDslTopLevelMethod(PATTERN_CALL);
+        dslExpr.addArgument( context.getVarExpr( pattern.getIdentifier()) );
+        if (context.isQuery()) {
+            Optional<Expression> declarationSource = declarationSpec.getDeclarationSource();
+            declarationSource.ifPresent(dslExpr::addArgument);
+        }
+        return dslExpr;
+    }
+
+    private void buildConstraints(PatternDescr pattern, Class<?> patternType, List<PatternConstraintParseResult> patternConstraintParseResults) {
+        boolean hasOOPath = false;
+        for (PatternConstraintParseResult patternConstraintParseResult : patternConstraintParseResults) {
+            // only one oopath per pattern is allowed
+            if (patternConstraintParseResult.drlxParseResult().isOOPath()) {
+                if (hasOOPath) {
+                    context.addCompilationError(new InvalidExpressionErrorResult("Only one oopath per pattern is allowed"));
+                    break;
+                } else {
+                    hasOOPath = true;
+                }
+            }
+            buildConstraint(pattern, patternType, patternConstraintParseResult);
+        }
+        if (hasOOPath) {
+            context.clearOOPathPatternExpr();
+        }
+    }
+
+    private DSLNode createSimpleConstraint( DrlxParseSuccess drlxParseResult, PatternDescr pattern ) {
+        return new PatternDSLSimpleConstraint( context, pattern, drlxParseResult );
+    }
 }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ConstraintOOPath.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ConstraintOOPath.java
index 984fe1a948..61cbbf7c97 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ConstraintOOPath.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/ConstraintOOPath.java
@@ -43,7 +43,7 @@ class ConstraintOOPath implements DSLNode {
         this.pattern = pattern;
         this.patternType = patternType;
         this.patternConstraintParseResult = patternConstraintParseResult;
-        this.expression = patternConstraintParseResult.getExpression();
+        this.expression = patternConstraintParseResult.expression();
         this.drlxParseResult = drlxParseResult;
     }
 
@@ -51,8 +51,8 @@ class ConstraintOOPath implements DSLNode {
     public void buildPattern() {
         final String patternIdentifierGenerated;
         // If the  outer pattern does not have a binding we generate it
-        if (patternConstraintParseResult.getPatternIdentifier() != null) {
-            patternIdentifierGenerated = patternConstraintParseResult.getPatternIdentifier();
+        if (patternConstraintParseResult.patternIdentifier() != null) {
+            patternIdentifierGenerated = patternConstraintParseResult.patternIdentifier();
         } else {
             patternIdentifierGenerated = context.getExprId(patternType, expression);
             context.addDeclaration(patternIdentifierGenerated, patternType, Optional.of(pattern), Optional.empty());
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternAccumulateConstraint.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternAccumulateConstraint.java
index 31739dbcb1..448c96dfe4 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternAccumulateConstraint.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternAccumulateConstraint.java
@@ -68,7 +68,7 @@ class PatternAccumulateConstraint implements DSLNode {
 
         constraintsByVar.forEach( (id, constraints) -> {
             pattern.setIdentifier(id);
-            new PatternDSLPattern(context, packageModel, pattern, constraints, null).buildPattern();
+            new ClassPatternDSL(context, packageModel, pattern, constraints, null).buildPattern();
         });
         pattern.setIdentifier(null);
     }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternConstraintParseResult.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternConstraintParseResult.java
index 1af3b3396c..82aee014a0 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternConstraintParseResult.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternConstraintParseResult.java
@@ -20,26 +20,4 @@ package org.drools.model.codegen.execmodel.generator.visitor.pattern;
 
 import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseResult;
 
-public class PatternConstraintParseResult {
-    private String expression;
-    private String patternIdentifier;
-    private DrlxParseResult drlxParseResult;
-
-    public PatternConstraintParseResult(String expression, String patternIdentifier, DrlxParseResult drlxParseResult) {
-        this.expression = expression;
-        this.patternIdentifier = patternIdentifier;
-        this.drlxParseResult = drlxParseResult;
-    }
-
-    public String getExpression() {
-        return expression;
-    }
-
-    public String getPatternIdentifier() {
-        return patternIdentifier;
-    }
-
-    public DrlxParseResult getDrlxParseResult() {
-        return drlxParseResult;
-    }
-}
+public record PatternConstraintParseResult(String expression, String patternIdentifier, DrlxParseResult drlxParseResult) { }
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java
index 6e1ec9d698..de1f4f6646 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSL.java
@@ -18,286 +18,36 @@
  */
 package org.drools.model.codegen.execmodel.generator.visitor.pattern;
 
-import com.github.javaparser.ast.expr.Expression;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
 import com.github.javaparser.ast.expr.MethodCallExpr;
-import org.drools.base.util.PropertyReactivityUtil;
-import org.drools.compiler.compiler.DescrBuildError;
 import org.drools.drl.ast.descr.AccumulateDescr;
 import org.drools.drl.ast.descr.BaseDescr;
 import org.drools.drl.ast.descr.ExprConstraintDescr;
 import org.drools.drl.ast.descr.PatternDescr;
-import org.drools.drl.ast.descr.PatternSourceDescr;
 import org.drools.model.codegen.execmodel.PackageModel;
-import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
-import org.drools.model.codegen.execmodel.generator.AggregateKey;
-import org.drools.model.codegen.execmodel.generator.ConstraintUtil;
 import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
-import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
 import org.drools.model.codegen.execmodel.generator.RuleContext;
-import org.drools.model.codegen.execmodel.generator.WindowReferenceGenerator;
-import org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintExpression;
-import org.drools.model.codegen.execmodel.generator.drlxparse.ConstraintParser;
-import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseFail;
-import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseResult;
 import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseSuccess;
-import org.drools.model.codegen.execmodel.generator.drlxparse.ParseResultVisitor;
-import org.drools.model.codegen.execmodel.generator.drlxparse.ParseResultVoidVisitor;
-import org.drools.model.codegen.execmodel.generator.drlxparse.SingleDrlxParseSuccess;
 import org.drools.model.codegen.execmodel.generator.visitor.DSLNode;
-import org.drools.model.codegen.execmodel.generator.visitor.FromVisitor;
-import org.kie.api.definition.rule.Watch;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static org.drools.compiler.rule.builder.PatternBuilder.lookAheadFieldsOfIdentifier;
-import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getPatternListenedProperties;
 import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.validateDuplicateBindings;
-import static org.drools.model.impl.NamesGenerator.generateName;
-import static org.drools.model.impl.VariableImpl.GENERATED_VARIABLE_PREFIX;
-import static org.drools.mvel.parser.printer.PrintUtil.printNode;
-import static org.drools.util.StreamUtils.optionalToStream;
 
 public abstract class PatternDSL implements DSLNode {
 
     protected final RuleContext context;
     protected final PackageModel packageModel;
     protected final PatternDescr pattern;
-    private final List<? extends BaseDescr> constraintDescrs;
-    protected Class<?> patternType;
+    protected final List<? extends BaseDescr> constraintDescrs;
 
-    PatternDSL(RuleContext context, PackageModel packageModel, PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
+    PatternDSL(RuleContext context, PackageModel packageModel, PatternDescr pattern, List<? extends BaseDescr> constraintDescrs) {
         this.context = context;
         this.packageModel = packageModel;
         this.pattern = pattern;
         this.constraintDescrs = constraintDescrs;
-        this.patternType = patternType;
-    }
-
-    public DeclarationSpec initPattern() {
-        generatePatternIdentifierIfMissing();
-        context.addPatternBinding(pattern.getIdentifier());
-        final Optional<Expression> declarationSource = buildFromDeclaration(pattern);
-        return context.addDeclaration(pattern.getIdentifier(), patternType, Optional.of(pattern), declarationSource);
-    }
-
-    private static boolean isPositional(BaseDescr constraint) {
-        return constraint instanceof ExprConstraintDescr &&
-                ((ExprConstraintDescr) constraint).getType() == ExprConstraintDescr.Type.POSITIONAL &&
-                !constraint.getText().contains( ":=" );
-    }
-
-    private Optional<Expression> buildFromDeclaration(PatternDescr pattern) {
-        Optional<PatternSourceDescr> source = Optional.ofNullable(pattern.getSource());
-        try {
-            patternType = context.getTypeResolver().resolveType( pattern.getObjectType() );
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException( e );
-        }
-        Optional<Expression> declarationSourceFrom = source.flatMap(new FromVisitor(context, patternType)::visit);
-        if (declarationSourceFrom.isPresent()) {
-            return declarationSourceFrom;
-        }
-        return source.flatMap(sourceDescr -> new WindowReferenceGenerator(packageModel, context.getTypeResolver()).visit(sourceDescr, context));
-    }
-
-    private void generatePatternIdentifierIfMissing() {
-        // the PatternDescr can be shared by multiple rules in case of rules inheritance, so its identifier has to
-        // be set atomically when rule generation is performed in parallel
-        synchronized (pattern) {
-            if (pattern.getIdentifier() == null) {
-                final String generatedName = generateName("pattern_" + patternType.getSimpleName());
-                final String patternNameAggregated = findFirstInnerBinding(constraintDescrs, patternType)
-                        .map(ib -> context.getAggregatePatternMap().putIfAbsent(new AggregateKey(ib, patternType), generatedName))
-                        .orElse(generatedName);
-                pattern.setIdentifier(GENERATED_VARIABLE_PREFIX + patternNameAggregated);
-            }
-        }
-    }
-
-    private Optional<String> findFirstInnerBinding(List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
-        return constraintDescrs.stream()
-                .map( constraint -> ConstraintExpression.createConstraintExpression( context, patternType, constraint, isPositional(constraint) ).getExpression() )
-                .map( DrlxParseUtil::parseExpression )
-                .filter( drlx -> drlx.getBind() != null )
-                .map( drlx -> drlx.getBind().asString() )
-                .findFirst();
-    }
-
-    private List<PatternConstraintParseResult> findAllConstraint(PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
-        ConstraintParser constraintParser = ConstraintParser.defaultConstraintParser(context, packageModel);
-        List<PatternConstraintParseResult> patternConstraintParseResults = new ArrayList<>();
-
-        for (BaseDescr constraint : constraintDescrs) {
-            List<PatternConstraintParseResult> patternConstraintParseResultsPerConstraintDescr = new ArrayList<>();
-            String patternIdentifier = pattern.getIdentifier();
-
-            boolean isPositional = isPositional(constraint);
-
-            ConstraintExpression constraintExpression = ConstraintExpression.createConstraintExpression(context, patternType, constraint, isPositional);
-            if (constraintExpression == null) {
-                continue;
-            }
-
-            DrlxParseResult drlxParseResult;
-            try {
-                context.setCurrentConstraintDescr(Optional.of(constraint));
-                drlxParseResult = constraintParser.drlxParse(patternType, patternIdentifier, constraintExpression, isPositional);
-            } finally {
-                context.resetCurrentConstraintDescr();
-            }
-
-            String expression = constraintExpression.getExpression();
-            if (drlxParseResult.isSuccess() && (( DrlxParseSuccess ) drlxParseResult).isRequiresSplit() && (( DrlxParseSuccess ) drlxParseResult).getExpr().isBinaryExpr()) {
-                String leftExpression = printNode(((SingleDrlxParseSuccess) drlxParseResult).getLeft().getExpression());
-                DrlxParseResult leftExpressionReparsed = constraintParser.drlxParse(patternType, patternIdentifier, leftExpression, isPositional);
-                patternConstraintParseResultsPerConstraintDescr.add(new PatternConstraintParseResult(leftExpression, patternIdentifier, leftExpressionReparsed));
-
-                String rightExpression = printNode(((SingleDrlxParseSuccess) drlxParseResult).getRight().getExpression());
-                DrlxParseResult rightExpressionReparsed = constraintParser.drlxParse(patternType, patternIdentifier, rightExpression, isPositional);
-                DrlxParseResult normalizedParseResult = ConstraintUtil.normalizeConstraint(rightExpressionReparsed);
-                patternConstraintParseResultsPerConstraintDescr.add(new PatternConstraintParseResult(rightExpression, patternIdentifier, normalizedParseResult));
-            } else {
-                DrlxParseResult normalizedParseResult = ConstraintUtil.normalizeConstraint(drlxParseResult);
-                patternConstraintParseResultsPerConstraintDescr.add(new PatternConstraintParseResult(expression, patternIdentifier, normalizedParseResult));
-            }
-
-            // Cast-check should be placed earlier than Null-check (calling the add method later means pushing the constraint earlier)
-            addNullSafeExpr(constraintParser, pattern.getIdentifier(), patternConstraintParseResultsPerConstraintDescr);
-            addImplicitCastExpr(constraintParser, pattern.getIdentifier(), patternConstraintParseResultsPerConstraintDescr);
-
-            patternConstraintParseResults.addAll(patternConstraintParseResultsPerConstraintDescr);
-        }
-
-        return patternConstraintParseResults;
-    }
-
-    private void addImplicitCastExpr(ConstraintParser constraintParser, String patternIdentifier, List<PatternConstraintParseResult> patternConstraintParseResults) {
-        final boolean hasInstanceOfExpr = patternConstraintParseResults.stream()
-                .anyMatch(r -> r.getDrlxParseResult().acceptWithReturnValue(new ParseResultVisitor<>() {
-                    @Override
-                    public Boolean onSuccess(DrlxParseSuccess t) {
-                        Expression expr = t.getExpr();
-                        return expr != null && expr.isInstanceOfExpr();
-                    }
-
-                    @Override
-                    public Boolean onFail(DrlxParseFail failure) {
-                        return false;
-                    }
-                }));
-
-        final Optional<Expression> implicitCastExpression =
-                patternConstraintParseResults.stream()
-                .flatMap(r -> optionalToStream(r.getDrlxParseResult().acceptWithReturnValue(new ParseResultVisitor<Optional<Expression>>() {
-                    @Override
-                    public Optional<Expression> onSuccess(DrlxParseSuccess t) {
-                        return t.getImplicitCastExpression();
-                    }
-
-                    @Override
-                    public Optional<Expression> onFail(DrlxParseFail failure) {
-                        return Optional.empty();
-                    }
-                })))
-                .findFirst();
-
-        implicitCastExpression.ifPresent(ce -> {
-            if(!hasInstanceOfExpr) {
-                String instanceOfExpression = printNode(ce);
-                DrlxParseResult instanceOfExpressionParsed = constraintParser.drlxParse(patternType, patternIdentifier, instanceOfExpression, false);
-                patternConstraintParseResults.add(0, new PatternConstraintParseResult(instanceOfExpression, patternIdentifier, instanceOfExpressionParsed));
-            }
-        });
-    }
-
-    private void addNullSafeExpr(ConstraintParser constraintParser, String patternIdentifier, List<PatternConstraintParseResult> patternConstraintParseResults) {
-        final List<Expression> nullSafeExpressions =
-                patternConstraintParseResults.stream()
-                                             .flatMap(r -> r.getDrlxParseResult().acceptWithReturnValue(new ParseResultVisitor<List<Expression>>() {
-
-                                                 @Override
-                                                 public List<Expression> onSuccess(DrlxParseSuccess t) {
-                                                     return t.getNullSafeExpressions();
-                                                 }
-
-                                                 @Override
-                                                 public List<Expression> onFail(DrlxParseFail failure) {
-                                                     return Collections.emptyList();
-                                                 }
-                                             }).stream())
-                                             .collect(Collectors.toList());
-
-        List<Expression> newNullSafeExpressions = reverseDistinct(nullSafeExpressions);
-
-        newNullSafeExpressions.forEach(expr -> {
-            String nullSafeExpression = printNode(expr);
-            DrlxParseResult nullSafeExpressionParsed = constraintParser.drlxParse(patternType, patternIdentifier, nullSafeExpression, false);
-            patternConstraintParseResults.add(0, new PatternConstraintParseResult(nullSafeExpression, patternIdentifier, nullSafeExpressionParsed));
-        });
-    }
-
-    private List<Expression> reverseDistinct(List<Expression> nullSafeExpressions) {
-        // distinct from the end of the list
-        Collections.reverse(nullSafeExpressions);
-        List<Expression> newNullSafeExpressions = nullSafeExpressions.stream().distinct().collect(Collectors.toList());
-        Collections.reverse(newNullSafeExpressions);
-        return newNullSafeExpressions;
-    }
-
-    void buildConstraint(PatternDescr pattern, Class<?> patternType, PatternConstraintParseResult patternConstraintParseResult) {
-        DrlxParseResult drlxParseResult = patternConstraintParseResult.getDrlxParseResult();
-
-        DrlxParseResult withBindingCheck = drlxParseResult.acceptWithReturnValue(new ParseResultVisitor<>() {
-            @Override
-            public DrlxParseResult onSuccess(DrlxParseSuccess drlxParseResult) {
-
-                String exprBinding = drlxParseResult.getExprBinding();
-                if (exprBinding == null && !drlxParseResult.isPredicate() && drlxParseResult.getImplicitCastExpression().isEmpty()) {
-                    return new DrlxParseFail(new DescrBuildError(context.getRuleDescr(), context.getRuleDescr(), "",
-                                                                 String.format("Predicate '%s' must be a Boolean expression", drlxParseResult.getOriginalDrlConstraint())));
-                } else {
-                    return drlxParseResult;
-                }
-            }
-
-            @Override
-            public DrlxParseResult onFail(DrlxParseFail failure) {
-                return failure;
-            }
-        });
-
-        withBindingCheck.accept(
-                new ParseResultVoidVisitor() {
-                    @Override
-                    public void onSuccess( DrlxParseSuccess drlxParseResult ) {
-                        DSLNode constraint = drlxParseResult.isOOPath() ?
-                            new ConstraintOOPath( context, packageModel, pattern, patternType, patternConstraintParseResult, drlxParseResult ) :
-                            createSimpleConstraint( drlxParseResult, pattern );
-                        constraint.buildPattern();
-                        registerUsedBindingInOr(drlxParseResult.getExprBinding());
-                    }
-
-                    @Override
-                    public void onFail( DrlxParseFail failure ) {
-                        if (failure.getError() != null) {
-                            context.addCompilationError( failure.getError() );
-                        }
-                    }
-                } );
-    }
-
-    private void registerUsedBindingInOr(String exprBinding) {
-        if(context.isNestedInsideOr()) {
-            context.getBindingOr().add(exprBinding);
-        }
     }
 
     @Override
@@ -309,10 +59,10 @@ public abstract class PatternDSL implements DSLNode {
             if (constraintDescrs.isEmpty() && !(pattern.getSource() instanceof AccumulateDescr)) {
                 context.addExpression(input(declarationSpec));
             } else {
-                final List<PatternConstraintParseResult> patternConstraintParseResults = findAllConstraint(pattern, constraintDescrs, patternType);
+                final List<PatternConstraintParseResult> patternConstraintParseResults = findAllConstraint(pattern, constraintDescrs);
                 final List<String> allBindings = patternConstraintParseResults
                         .stream()
-                        .map(p -> p.getDrlxParseResult().acceptWithReturnValue( DrlxParseSuccess::getExprBinding ))
+                        .map(p -> p.drlxParseResult().acceptWithReturnValue(DrlxParseSuccess::getExprBinding))
                         .filter(Objects::nonNull)
                         .collect(Collectors.toList());
 
@@ -327,42 +77,22 @@ public abstract class PatternDSL implements DSLNode {
         }
     }
 
-    Set<String> getSettableWatchedProps() {
-        Set<String> settableWatchedProps = new HashSet<>();
-        Collection<String> settableProps = PropertyReactivityUtil.getAccessibleProperties(patternType);
 
-        List<String> propertiesInWatch = getPatternListenedProperties(pattern);
-        propertiesInWatch.forEach(prop -> populateSettableWatchedProps(prop, settableProps, settableWatchedProps, true));
-
-        if (context.isPropertyReactive(patternType)) {
-            Collection<String> lookAheadProps = lookAheadFieldsOfIdentifier(context.getRuleDescr(), pattern);
-            lookAheadProps.forEach(prop -> populateSettableWatchedProps(prop, settableProps, settableWatchedProps, false)); // okay to have non-settable prop in lookAhead
-        }
-        
-        return settableWatchedProps;
+    protected static boolean isPositional(BaseDescr constraint) {
+        return constraint instanceof ExprConstraintDescr &&
+                ((ExprConstraintDescr) constraint).getType() == ExprConstraintDescr.Type.POSITIONAL &&
+                !constraint.getText().contains(":=");
     }
 
-    private void populateSettableWatchedProps(String property, Collection<String> settableProps, Set<String> settableWatchedProps, boolean raiseErrorForNonSettableOrDuplicatedProp) {
-        String trimmedProperty = property.trim();
-        String actualProperty = trimmedProperty;
-        if (trimmedProperty.startsWith("!")) {
-            actualProperty = property.substring(1).trim();
-            trimmedProperty = "!" + actualProperty;
-        }
-        if (actualProperty.equals("*") || settableProps.contains(actualProperty)) {
-            if (raiseErrorForNonSettableOrDuplicatedProp && (settableWatchedProps.contains(actualProperty) || settableWatchedProps.contains("!" + actualProperty))) {
-                context.addCompilationError(new InvalidExpressionErrorResult("Duplicate property " + actualProperty + " in @" + Watch.class.getSimpleName() + " annotation"));
-                return;
-            }
-            settableWatchedProps.add(trimmedProperty);
-        } else if (raiseErrorForNonSettableOrDuplicatedProp) {
-            context.addCompilationError(new InvalidExpressionErrorResult("Unknown property " + actualProperty + " in @watch annotation"));
-        }
-    }
+    public abstract DeclarationSpec initPattern();
+
+    protected abstract List<PatternConstraintParseResult> findAllConstraint(PatternDescr pattern, List<? extends BaseDescr> constraintDescrs);
 
     protected abstract void buildPattern(DeclarationSpec declarationSpec, List<PatternConstraintParseResult> patternConstraintParseResults);
 
-    protected abstract MethodCallExpr input(DeclarationSpec declarationSpec);
+    protected abstract String getPatternTypeName();
 
-    protected abstract DSLNode createSimpleConstraint( DrlxParseSuccess drlxParseResult, PatternDescr pattern );
-}
+    protected abstract Class<?> getPatternType();
+
+    protected abstract MethodCallExpr input(DeclarationSpec declarationSpec);
+}
\ No newline at end of file
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSLPattern.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSLPattern.java
deleted file mode 100644
index 556b870e2b..0000000000
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternDSLPattern.java
+++ /dev/null
@@ -1,136 +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.drools.model.codegen.execmodel.generator.visitor.pattern;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import com.github.javaparser.ast.expr.Expression;
-import com.github.javaparser.ast.expr.MethodCallExpr;
-import com.github.javaparser.ast.expr.StringLiteralExpr;
-import org.drools.drl.ast.descr.BaseDescr;
-import org.drools.drl.ast.descr.PatternDescr;
-import org.drools.model.codegen.execmodel.PackageModel;
-import org.drools.model.codegen.execmodel.errors.InvalidExpressionErrorResult;
-import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
-import org.drools.model.codegen.execmodel.generator.RuleContext;
-import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseSuccess;
-import org.drools.model.codegen.execmodel.generator.visitor.DSLNode;
-import org.kie.api.definition.rule.Watch;
-
-import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.findLastMethodInChain;
-import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.findRootNodeViaScope;
-import static org.drools.model.codegen.execmodel.generator.DslMethodNames.NO_OP_EXPR;
-import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PASSIVE_CALL;
-import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PATTERN_CALL;
-import static org.drools.model.codegen.execmodel.generator.DslMethodNames.WATCH_CALL;
-import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createDslTopLevelMethod;
-
-class PatternDSLPattern extends PatternDSL {
-
-    protected PatternDSLPattern(RuleContext context, PackageModel packageModel, PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, Class<?> patternType) {
-        super(context, packageModel, pattern, constraintDescrs, patternType);
-    }
-
-    @Override
-    protected void buildPattern(DeclarationSpec declarationSpec, List<PatternConstraintParseResult> patternConstraintParseResults) {
-        MethodCallExpr patternExpression = createPatternExpression(pattern, declarationSpec);
-
-        List<Expression> exprs = new ArrayList<>();
-        context.pushExprPointer(exprs::add);
-        buildConstraints(pattern, patternType, patternConstraintParseResults);
-        context.popExprPointer();
-
-        List<Expression> additionalPatterns = new ArrayList<>();
-        for (Expression expr : exprs) {
-            Optional<Expression> rootScope = findRootNodeViaScope(expr );
-            if ( rootScope.isPresent() && (( MethodCallExpr ) rootScope.get()).getNameAsString().equals( PATTERN_CALL ) ) {
-                additionalPatterns.add( expr );
-            } else {
-                MethodCallExpr currentExpr = ( MethodCallExpr ) expr;
-                MethodCallExpr lastMethodInChain = findLastMethodInChain(currentExpr);
-                if (!NO_OP_EXPR.equals(lastMethodInChain.getNameAsString())) {
-                    lastMethodInChain.setScope(patternExpression);
-                    patternExpression = currentExpr;
-                }
-            }
-        }
-
-        if (pattern.isQuery()) {
-            patternExpression = new MethodCallExpr( patternExpression, PASSIVE_CALL );
-        }
-
-        context.addExpression( addWatchToPattern( patternExpression ) );
-        additionalPatterns.forEach( context::addExpression );
-    }
-
-    @Override
-    public MethodCallExpr input(DeclarationSpec declarationSpec) {
-        return addWatchToPattern( createPatternExpression(pattern, declarationSpec) );
-    }
-
-    private MethodCallExpr addWatchToPattern( MethodCallExpr patternExpression ) {
-        Set<String> settableWatchedProps = getSettableWatchedProps();
-        if ( !settableWatchedProps.isEmpty() ) {
-            if (context.isPropertyReactive(patternType)) {
-                patternExpression = new MethodCallExpr(patternExpression, WATCH_CALL);
-                settableWatchedProps.stream().map(StringLiteralExpr::new).forEach(patternExpression::addArgument);
-            } else {
-                context.addCompilationError(new InvalidExpressionErrorResult("Wrong usage of @" + Watch.class.getSimpleName() + " annotation on class " + patternType.getName() + " that is not annotated as @PropertyReactive"));
-            }
-        }
-        return patternExpression;
-    }
-
-    private MethodCallExpr createPatternExpression(PatternDescr pattern, DeclarationSpec declarationSpec) {
-        MethodCallExpr dslExpr = createDslTopLevelMethod(PATTERN_CALL);
-        dslExpr.addArgument( context.getVarExpr( pattern.getIdentifier()) );
-        if (context.isQuery()) {
-            Optional<Expression> declarationSource = declarationSpec.getDeclarationSource();
-            declarationSource.ifPresent(dslExpr::addArgument);
-        }
-        return dslExpr;
-    }
-
-    private void buildConstraints(PatternDescr pattern, Class<?> patternType, List<PatternConstraintParseResult> patternConstraintParseResults) {
-        boolean hasOOPath = false;
-        for (PatternConstraintParseResult patternConstraintParseResult : patternConstraintParseResults) {
-            // only one oopath per pattern is allowed
-            if (patternConstraintParseResult.getDrlxParseResult().isOOPath()) {
-                if (hasOOPath) {
-                    context.addCompilationError(new InvalidExpressionErrorResult("Only one oopath per pattern is allowed"));
-                    break;
-                } else {
-                    hasOOPath = true;
-                }
-            }
-            buildConstraint(pattern, patternType, patternConstraintParseResult);
-        }
-        if (hasOOPath) {
-            context.clearOOPathPatternExpr();
-        }
-    }
-
-    @Override
-    protected DSLNode createSimpleConstraint( DrlxParseSuccess drlxParseResult, PatternDescr pattern ) {
-        return new PatternDSLSimpleConstraint( context, pattern, drlxParseResult );
-    }
-}
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternVisitor.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternVisitor.java
index 8fd6e2c59b..8c84f66cc4 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternVisitor.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PatternVisitor.java
@@ -62,11 +62,14 @@ public class PatternVisitor {
             patternType = context.getTypeResolver().resolveType(className);
             packageModel.addOtnsClass(patternType);
         } catch (ClassNotFoundException e) {
+            if (context.arePrototypesAllowed()) {
+                return new PrototypePatternDSL(context, packageModel, pattern, constraintDescrs, className);
+            }
             context.addCompilationError( new InvalidExpressionErrorResult( "Unable to find class: " + className ) );
             return () -> { };
         }
 
-        return new PatternDSLPattern(context, packageModel, pattern, constraintDescrs, patternType);
+        return new ClassPatternDSL(context, packageModel, pattern, constraintDescrs, patternType);
     }
 
     private DSLNode parsePatternWithClass(PatternDescr pattern, String className) {
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PrototypePatternDSL.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PrototypePatternDSL.java
new file mode 100644
index 0000000000..cd5c810e32
--- /dev/null
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/visitor/pattern/PrototypePatternDSL.java
@@ -0,0 +1,132 @@
+/**
+ * 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.drools.model.codegen.execmodel.generator.visitor.pattern;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.github.javaparser.ast.expr.BinaryExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.ast.descr.PatternDescr;
+import org.drools.model.Index;
+import org.drools.model.codegen.execmodel.PackageModel;
+import org.drools.model.codegen.execmodel.generator.DeclarationSpec;
+import org.drools.model.codegen.execmodel.generator.DrlxParseUtil;
+import org.drools.model.codegen.execmodel.generator.RuleContext;
+import org.drools.model.codegen.execmodel.generator.drlxparse.DrlxParseSuccess;
+import org.drools.model.codegen.execmodel.generator.drlxparse.SingleDrlxParseSuccess;
+import org.drools.mvel.parser.ast.expr.DrlxExpression;
+
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PROTO_EXPR_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.PROTO_PATTERN_CALL;
+import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createProtoDslTopLevelMethod;
+import static org.drools.model.impl.VariableImpl.GENERATED_VARIABLE_PREFIX;
+
+public class PrototypePatternDSL extends PatternDSL {
+
+    private final String patternName;
+
+    PrototypePatternDSL(RuleContext context, PackageModel packageModel, PatternDescr pattern, List<? extends BaseDescr> constraintDescrs, String patternName) {
+        super(context, packageModel, pattern, constraintDescrs);
+        this.patternName = patternName;
+    }
+
+    @Override
+    protected List<PatternConstraintParseResult> findAllConstraint(PatternDescr pattern, List<? extends BaseDescr> constraintDescrs) {
+        List<PatternConstraintParseResult> patternConstraintParseResults = new ArrayList<>();
+
+        for (BaseDescr constraint : constraintDescrs) {
+            String patternIdentifier = pattern.getIdentifier();
+            String expression = constraint.toString();
+
+            DrlxExpression drlx = DrlxParseUtil.parseExpression( expression );
+            var drlxParse = new SingleDrlxParseSuccess(null, patternIdentifier, drlxToExpression(drlx), null);
+            if (drlx.getBind() != null) {
+                drlxParse.setExprBinding(drlx.getBind().asString());
+            }
+            patternConstraintParseResults.add(new PatternConstraintParseResult(expression, patternIdentifier, drlxParse));
+        }
+
+        return patternConstraintParseResults;
+    }
+
+    private Expression drlxToExpression(DrlxExpression drlx) {
+        Expression expression = drlx.getExpr();
+
+        if (expression instanceof BinaryExpr bExpr) {
+            MethodCallExpr dslExpr = new MethodCallExpr(PROTO_EXPR_CALL);
+            dslExpr.addArgument( new StringLiteralExpr(bExpr.getLeft().asNameExpr().getName().asString()) );
+            dslExpr.addArgument( Index.ConstraintType.class.getCanonicalName() + "." + DrlxParseUtil.toConstraintType(bExpr.getOperator() ) );
+            dslExpr.addArgument( bExpr.getRight() );
+            return dslExpr;
+        }
+
+        throw new UnsupportedOperationException("Unknown expression type: " + expression.getClass().getSimpleName());
+    }
+
+    @Override
+    public DeclarationSpec initPattern() {
+        generatePatternIdentifierIfMissing();
+        context.addPatternBinding(pattern.getIdentifier());
+        return context.addPrototypeDeclaration(pattern.getIdentifier(), pattern.getObjectType());
+    }
+
+    private void generatePatternIdentifierIfMissing() {
+        // the PatternDescr can be shared by multiple rules in case of rules inheritance, so its identifier has to
+        // be set atomically when rule generation is performed in parallel
+        synchronized (pattern) {
+            if (pattern.getIdentifier() == null) {
+                pattern.setIdentifier(GENERATED_VARIABLE_PREFIX + patternName);
+            }
+        }
+    }
+
+    @Override
+    protected void buildPattern(DeclarationSpec declarationSpec, List<PatternConstraintParseResult> patternConstraintParseResults) {
+        MethodCallExpr patternExpression = createPatternExpression(pattern);
+        for (PatternConstraintParseResult parseResult : patternConstraintParseResults) {
+            patternExpression = ((DrlxParseSuccess) parseResult.drlxParseResult()).getExpr().asMethodCallExpr().setScope(patternExpression);
+        }
+        context.addExpression( patternExpression );
+    }
+
+    @Override
+    protected String getPatternTypeName() {
+        return patternName;
+    }
+
+    @Override
+    protected Class<?> getPatternType() {
+        return null;
+    }
+
+    @Override
+    protected MethodCallExpr input(DeclarationSpec declarationSpec) {
+        return createPatternExpression(pattern);
+    }
+
+    private MethodCallExpr createPatternExpression(PatternDescr pattern) {
+        MethodCallExpr dslExpr = createProtoDslTopLevelMethod(PROTO_PATTERN_CALL);
+        dslExpr.addArgument( context.getVarExpr( pattern.getIdentifier()) );
+        return dslExpr;
+    }
+}
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/ModelMainCompilationPhase.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/ModelMainCompilationPhase.java
index 5c93e29685..c66d6e2fc0 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/ModelMainCompilationPhase.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/ModelMainCompilationPhase.java
@@ -18,6 +18,11 @@
  */
 package org.drools.model.codegen.execmodel.processors;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Function;
+
 import org.drools.compiler.builder.PackageRegistryManager;
 import org.drools.compiler.builder.impl.BuildResultCollector;
 import org.drools.compiler.builder.impl.BuildResultCollectorImpl;
@@ -27,9 +32,9 @@ import org.drools.compiler.builder.impl.processors.AccumulateFunctionCompilation
 import org.drools.compiler.builder.impl.processors.CompilationPhase;
 import org.drools.compiler.builder.impl.processors.FunctionCompilationPhase;
 import org.drools.compiler.builder.impl.processors.GlobalCompilationPhase;
+import org.drools.compiler.builder.impl.processors.IteratingPhase;
 import org.drools.compiler.builder.impl.processors.RuleValidator;
 import org.drools.compiler.builder.impl.processors.SinglePackagePhaseFactory;
-import org.drools.compiler.builder.impl.processors.IteratingPhase;
 import org.drools.compiler.builder.impl.processors.WindowDeclarationCompilationPhase;
 import org.drools.compiler.lang.descr.CompositePackageDescr;
 import org.drools.kiesession.rulebase.InternalKnowledgeBase;
@@ -39,11 +44,6 @@ import org.drools.model.codegen.execmodel.PackageSourceManager;
 import org.kie.internal.builder.KnowledgeBuilderConfiguration;
 import org.kie.internal.builder.KnowledgeBuilderResult;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.function.Function;
-
 public class ModelMainCompilationPhase<T> implements CompilationPhase {
 
     private final PackageModelManager packageModels;
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/KogitoKnowledgeBuilderConfigurationImpl.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/KogitoKnowledgeBuilderConfigurationImpl.java
deleted file mode 100644
index d5e331094c..0000000000
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/KogitoKnowledgeBuilderConfigurationImpl.java
+++ /dev/null
@@ -1,53 +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.drools.model.codegen.project;
-
-import java.util.NoSuchElementException;
-
-import org.drools.compiler.builder.impl.KnowledgeBuilderConfigurationImpl;
-import org.drools.codegen.common.DroolsModelBuildContext;
-import org.kie.internal.builder.conf.KnowledgeBuilderOption;
-import org.kie.internal.builder.conf.MultiValueKieBuilderOption;
-import org.kie.internal.builder.conf.SingleValueKieBuilderOption;
-import org.kie.internal.conf.CompositeConfiguration;
-import org.kie.internal.utils.ChainedProperties;
-
-public class KogitoKnowledgeBuilderConfigurationImpl extends KnowledgeBuilderConfigurationImpl {
-
-    public static KogitoKnowledgeBuilderConfigurationImpl fromContext(DroolsModelBuildContext buildContext) {
-        throw new UnsupportedOperationException();
-//        KogitoKnowledgeBuilderConfigurationImpl conf = new KogitoKnowledgeBuilderConfigurationImpl(buildContext.getClassLoader());
-//        for (String prop : buildContext.getApplicationProperties()) {
-//            if (prop.startsWith("drools")) {
-//                conf.setProperty(prop, buildContext.getApplicationProperty(prop).orElseThrow(NoSuchElementException::new));
-//            }
-//        }
-//        return conf;
-    }
-
-
-    public KogitoKnowledgeBuilderConfigurationImpl(CompositeConfiguration<KnowledgeBuilderOption, SingleValueKieBuilderOption, MultiValueKieBuilderOption> compConfig, ClassLoader classLoader, ChainedProperties chainedProperties) {
-        super(compConfig);
-    }
-
-    @Override
-    protected ClassLoader getFunctionFactoryClassLoader() {
-        return KogitoKnowledgeBuilderConfigurationImpl.class.getClassLoader();
-    }
-}
diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/FactTemplateTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/PrototypeTest.java
similarity index 75%
rename from drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/FactTemplateTest.java
rename to drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/PrototypeTest.java
index 6bdde3cf2d..7e3ccd1154 100644
--- a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/FactTemplateTest.java
+++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/PrototypeTest.java
@@ -18,9 +18,18 @@
  */
 package org.drools.model.codegen.execmodel;
 
-import org.drools.base.facttemplates.Event;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplateObjectType;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiPredicate;
+import java.util.stream.Collectors;
+
+import org.drools.base.prototype.PrototypeObjectType;
 import org.drools.core.ClockType;
 import org.drools.core.reteoo.CompositeObjectSinkAdapter;
 import org.drools.core.reteoo.EntryPointNode;
@@ -30,10 +39,6 @@ import org.drools.model.ConstraintOperator;
 import org.drools.model.DSL;
 import org.drools.model.Index;
 import org.drools.model.Model;
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeExpression;
-import org.drools.model.PrototypeFact;
-import org.drools.model.PrototypeVariable;
 import org.drools.model.Query;
 import org.drools.model.Rule;
 import org.drools.model.Variable;
@@ -41,11 +46,18 @@ import org.drools.model.codegen.execmodel.domain.Person;
 import org.drools.model.codegen.execmodel.domain.Result;
 import org.drools.model.functions.Function1;
 import org.drools.model.impl.ModelImpl;
+import org.drools.model.prototype.PrototypeExpression;
+import org.drools.model.prototype.PrototypeVariable;
 import org.drools.modelcompiler.KieBaseBuilder;
 import org.junit.Test;
 import org.kie.api.KieBase;
 import org.kie.api.KieServices;
 import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeEventInstance;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
 import org.kie.api.runtime.KieSession;
 import org.kie.api.runtime.KieSessionConfiguration;
 import org.kie.api.runtime.conf.ClockTypeOption;
@@ -54,17 +66,6 @@ import org.kie.api.runtime.rule.Row;
 import org.kie.api.runtime.rule.ViewChangedEventListener;
 import org.kie.api.time.SessionPseudoClock;
 
-import java.math.BigDecimal;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.function.BiPredicate;
-import java.util.stream.Collectors;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
 import static org.drools.model.DSL.accFunction;
@@ -80,18 +81,15 @@ import static org.drools.model.PatternDSL.pattern;
 import static org.drools.model.PatternDSL.query;
 import static org.drools.model.PatternDSL.reactOn;
 import static org.drools.model.PatternDSL.rule;
-import static org.drools.model.PrototypeDSL.field;
-import static org.drools.model.PrototypeDSL.protoPattern;
-import static org.drools.model.PrototypeDSL.prototype;
-import static org.drools.model.PrototypeDSL.variable;
-import static org.drools.model.PrototypeExpression.fixedValue;
-import static org.drools.model.PrototypeExpression.prototypeField;
-import static org.drools.model.PrototypeExpression.thisPrototype;
 import static org.drools.model.codegen.execmodel.BaseModelTest.getObjectsIntoList;
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedEvent;
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedFact;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
+import static org.drools.model.prototype.PrototypeExpression.fixedValue;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
+import static org.drools.model.prototype.PrototypeExpression.thisPrototype;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
 
-public class FactTemplateTest {
+public class PrototypeTest {
 
     private static final ConstraintOperator listContainsOp = new ConstraintOperator() {
         @Override
@@ -108,7 +106,7 @@ public class FactTemplateTest {
     private static final ConstraintOperator existsFieldOp = new ConstraintOperator() {
         @Override
         public <T, V> BiPredicate<T, V> asPredicate() {
-            return (t,v) -> ((PrototypeFact) t).has((String) v);
+            return (t,v) -> ((PrototypeFactInstance) t).has((String) v);
         }
 
         @Override
@@ -119,15 +117,15 @@ public class FactTemplateTest {
 
     @Test
     public void testAlphaWithPropertyReactivity() {
-        testAlpha(prototype( "org.drools.Person", field("name", String.class), field("age", Integer.class) ), true);
+        testAlpha(prototype( "org.drools.Person").withField("name", String.class).withField("age", Integer.class).asFact(), true);
     }
 
     @Test
     public void testAlphaWithoutPropertyReactivity() {
-        testAlpha(prototype( "org.drools.Person" ), false);
+        testAlpha(prototype( "org.drools.Person" ).asFact(), false);
     }
 
-    private void testAlpha(Prototype personFact, boolean hasFields) {
+    private void testAlpha(PrototypeFact personFact, boolean hasFields) {
         PrototypeVariable markV = variable(personFact);
 
         Rule rule = rule( "alpha" )
@@ -144,11 +142,11 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        assertThat(hasFactTemplateObjectType(ksession, "Person")).isTrue();
+        assertThat(hasPrototypeObjectType(ksession, "org.drools.Person")).isTrue();
 
-        Fact mark = createMapBasedFact(personFact);
-        mark.set( "name", "Mark" );
-        mark.set( "age", 40 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 40 );
 
         FactHandle fh = ksession.insert( mark );
         assertThat(ksession.fireAllRules()).isEqualTo(1);
@@ -156,7 +154,7 @@ public class FactTemplateTest {
         Collection<Result> results = getObjectsIntoList(ksession, Result.class);
         assertThat(results).contains(new Result("Found a 40 years old Mark"));
 
-        mark.set( "age", 41 );
+        mark.put("age", 41 );
         ksession.update(fh, mark, "age");
         // property reactivity should prevent this firing
         assertThat(ksession.fireAllRules()).isEqualTo(hasFields ? 0 : 1);
@@ -169,7 +167,7 @@ public class FactTemplateTest {
     @Test
     public void testExpressionAlphaConstraint() {
         // DROOLS-7075
-        Prototype testPrototype = prototype( "test" );
+        PrototypeFact testPrototype = prototype( "test" ).asFact();
         PrototypeVariable testV = variable(testPrototype);
 
         Rule rule = rule( "alpha" )
@@ -186,14 +184,14 @@ public class FactTemplateTest {
         KieBase kieBase = KieBaseBuilder.createKieBaseFromModel( model );
         KieSession ksession = kieBase.newKieSession();
 
-        Fact testFact = createMapBasedFact(testPrototype);
-        testFact.set( "fieldA", 12 );
-        testFact.set( "fieldB", 8 );
+        PrototypeFactInstance testFact = testPrototype.newInstance();
+        testFact.put("fieldA", 12 );
+        testFact.put("fieldB", 8 );
 
         FactHandle fh = ksession.insert( testFact );
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        testFact.set( "fieldC", 5 );
+        testFact.put("fieldC", 5 );
         ksession.update(fh, testFact, "fieldC");
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
@@ -201,7 +199,7 @@ public class FactTemplateTest {
     @Test
     public void testExistsField() {
         // DROOLS-7075
-        Prototype testPrototype = prototype( "test" );
+        PrototypeFact testPrototype = prototype( "test" ).asFact();
         PrototypeVariable testV = variable(testPrototype);
 
         Rule rule = rule( "alpha" )
@@ -217,20 +215,20 @@ public class FactTemplateTest {
         KieBase kieBase = KieBaseBuilder.createKieBaseFromModel( model );
         KieSession ksession = kieBase.newKieSession();
 
-        Fact testFact = createMapBasedFact(testPrototype);
-        testFact.set( "fieldB", 8 );
+        PrototypeFactInstance testFact = testPrototype.newInstance();
+        testFact.put("fieldB", 8 );
 
         FactHandle fh = ksession.insert( testFact );
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        testFact.set( "fieldA", null );
+        testFact.put("fieldA", null );
         ksession.update(fh, testFact, "fieldA");
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
 
     @Test
     public void testNotNull() {
-        Prototype personFact = prototype( "org.drools.Person" );
+        PrototypeFact personFact = prototype( "org.drools.Person" ).asFact();
         PrototypeVariable markV = variable(personFact);
 
         Rule rule = rule("alpha")
@@ -247,14 +245,14 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact unknown = createMapBasedFact(personFact);
-        unknown.set( "age", 40 );
+        PrototypeFactInstance unknown = personFact.newInstance();
+        unknown.put("age", 40 );
         ksession.insert( unknown );
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact mark = createMapBasedFact(personFact);
-        mark.set( "name", "Mark" );
-        mark.set( "age", 40 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 40 );
         ksession.insert( mark );
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
@@ -263,7 +261,7 @@ public class FactTemplateTest {
     public void testBeta() {
         Result result = new Result();
 
-        Prototype personFact = prototype( "org.drools.Person", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.Person").withField("name").withField("age").asFact();
 
         PrototypeVariable markV = variable( personFact );
         PrototypeVariable olderV = variable( personFact );
@@ -283,19 +281,19 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        assertThat(hasFactTemplateObjectType(ksession, "Person")).isTrue();
+        assertThat(hasPrototypeObjectType(ksession, "org.drools.Person")).isTrue();
 
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", 37 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 37 );
 
-        Fact edson = createMapBasedFact( personFact );
-        edson.set( "name", "Edson" );
-        edson.set( "age", 35 );
+        PrototypeFactInstance edson = personFact.newInstance();
+        edson.put("name", "Edson" );
+        edson.put("age", 35 );
 
-        Fact mario = createMapBasedFact( personFact );
-        mario.set( "name", "Mario" );
-        mario.set( "age", 40 );
+        PrototypeFactInstance mario = personFact.newInstance();
+        mario.put("name", "Mario" );
+        mario.put("age", 40 );
 
         FactHandle markFH = ksession.insert(mark);
         FactHandle edsonFH = ksession.insert(edson);
@@ -309,7 +307,7 @@ public class FactTemplateTest {
         ksession.fireAllRules();
         assertThat(result.getValue()).isNull();
 
-        mark.set( "age", 34 );
+        mark.put("age", 34 );
         ksession.update( markFH, mark );
 
         ksession.fireAllRules();
@@ -319,7 +317,7 @@ public class FactTemplateTest {
     @Test
     public void testExpressionBetaConstraint() {
         // DROOLS-7075
-        Prototype testPrototype = prototype( "test" );
+        PrototypeFact testPrototype = prototype( "test" ).asFact();
         PrototypeVariable test1V = variable(testPrototype);
         PrototypeVariable test2V = variable(testPrototype);
 
@@ -338,24 +336,24 @@ public class FactTemplateTest {
         KieBase kieBase = KieBaseBuilder.createKieBaseFromModel( model );
         KieSession ksession = kieBase.newKieSession();
 
-        Fact testFact1 = createMapBasedFact(testPrototype);
-        testFact1.set( "fieldA", 12 );
+        PrototypeFactInstance testFact1 = testPrototype.newInstance();
+        testFact1.put("fieldA", 12 );
         FactHandle fh1 = ksession.insert( testFact1 );
 
-        Fact testFact2 = createMapBasedFact(testPrototype);
-        testFact2.set( "fieldB", 8 );
+        PrototypeFactInstance testFact2 = testPrototype.newInstance();
+        testFact2.put("fieldB", 8 );
         FactHandle fh2 = ksession.insert( testFact2 );
 
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        testFact2.set( "fieldC", 5 );
+        testFact2.put("fieldC", 5 );
         ksession.update(fh2, testFact2, "fieldC");
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
 
     @Test
     public void testBetaMixingClassAndFact() {
-        Prototype personFact = prototype( "org.drools.FactPerson", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.FactPerson").withField("name").withField("age").asFact();
 
         PrototypeVariable markV = variable( personFact );
 
@@ -381,11 +379,11 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        assertThat(hasFactTemplateObjectType(ksession, "FactPerson")).isTrue();
-        
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", 37 );
+        assertThat(hasPrototypeObjectType(ksession, "org.drools.FactPerson")).isTrue();
+
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 37 );
 
         ksession.insert( mark );
 
@@ -398,14 +396,14 @@ public class FactTemplateTest {
         assertThat(results).contains(new Result("Mario is older than Mark"));
     }
 
-    private boolean hasFactTemplateObjectType( KieSession ksession, String name ) {
-        return getFactTemplateObjectTypeNode( ksession, name ) != null;
+    private boolean hasPrototypeObjectType(KieSession ksession, String name ) {
+        return getPrototypeObjectTypeNode(ksession, name ) != null;
     }
 
-    private ObjectTypeNode getFactTemplateObjectTypeNode( KieSession ksession, String name ) {
+    private ObjectTypeNode getPrototypeObjectTypeNode(KieSession ksession, String name ) {
         EntryPointNode epn = ((InternalKnowledgeBase) ksession.getKieBase()).getRete().getEntryPointNodes().values().iterator().next();
         for (ObjectTypeNode otn : epn.getObjectTypeNodes().values()) {
-            if (otn.getObjectType() instanceof FactTemplateObjectType && (( FactTemplateObjectType ) otn.getObjectType()).getFactTemplate().getName().equals( name )) {
+            if (otn.getObjectType() instanceof PrototypeObjectType && ((PrototypeObjectType) otn.getObjectType()).getPrototype().getFullName().equals(name )) {
                 return otn;
             }
         }
@@ -414,7 +412,7 @@ public class FactTemplateTest {
 
     @Test
     public void testIndexedAlpha() {
-        Prototype personFact = prototype( "org.drools.Person", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.Person").withField("name").withField("age").asFact();
 
         PrototypeVariable personV = variable( personFact );
 
@@ -450,12 +448,12 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        ObjectTypeNode otn = getFactTemplateObjectTypeNode( ksession, "Person" );
+        ObjectTypeNode otn = getPrototypeObjectTypeNode(ksession, "org.drools.Person" );
         assertThat(((CompositeObjectSinkAdapter) otn.getObjectSinkPropagator()).getHashedSinkMap().size()).isEqualTo(3);
 
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", 40 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 40 );
 
         ksession.insert( mark );
         ksession.fireAllRules();
@@ -467,7 +465,7 @@ public class FactTemplateTest {
 
     @Test
     public void testAccumulate() {
-        Prototype personFact = prototype( "org.drools.Person", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.Person").withField("name").withField("age").asFact();
 
         PrototypeVariable person = variable( personFact );
 
@@ -490,19 +488,19 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", 37 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 37 );
         ksession.insert( mark );
 
-        Fact edson = createMapBasedFact( personFact );
-        edson.set( "name", "Edson" );
-        edson.set( "age", 35 );
+        PrototypeFactInstance edson = personFact.newInstance();
+        edson.put("name", "Edson" );
+        edson.put("age", 35 );
         ksession.insert( edson );
 
-        Fact mario = createMapBasedFact( personFact );
-        mario.set( "name", "Mario" );
-        mario.set( "age", 40 );
+        PrototypeFactInstance mario = personFact.newInstance();
+        mario.put("name", "Mario" );
+        mario.put("age", 40 );
         ksession.insert( mario );
 
         ksession.fireAllRules();
@@ -511,8 +509,8 @@ public class FactTemplateTest {
 
     @Test
     public void testQuery() {
-        Prototype customerFact = prototype( "customer" );
-        Prototype addressFact = prototype( "address" );
+        PrototypeFact customerFact = prototype( "customer" ).asFact();
+        PrototypeFact addressFact = prototype( "address" ).asFact();
 
         PrototypeVariable customerV = variable( customerFact, "c" );
         PrototypeVariable addressV = variable( addressFact, "a" );
@@ -529,16 +527,16 @@ public class FactTemplateTest {
         MaterializedViewChangedEventListener listener = new MaterializedViewChangedEventListener();
         ksession.openLiveQuery("Q0", new Object[0], listener);
 
-        Fact address1 = createMapBasedFact( addressFact );
-        address1.set("id", "100001");
-        address1.set("customer_id", "1001");
-        address1.set("street", "42 Main Street");
+        PrototypeFactInstance address1 = addressFact.newInstance();
+        address1.put("id", "100001");
+        address1.put("customer_id", "1001");
+        address1.put("street", "42 Main Street");
         FactHandle fhA1 = ksession.insert( address1 );
         ksession.fireAllRules();
 
-        Fact customer1 = createMapBasedFact( customerFact );
-        customer1.set("id", "1001");
-        customer1.set("first_name", "Sally");
+        PrototypeFactInstance customer1 = customerFact.newInstance();
+        customer1.put("id", "1001");
+        customer1.put("first_name", "Sally");
         ksession.insert( customer1 );
         ksession.fireAllRules();
 
@@ -546,10 +544,10 @@ public class FactTemplateTest {
         assertThat(listener.updates).isEqualTo(0);
         assertThat(listener.deletes).isEqualTo(0);
 
-        Fact address2 = createMapBasedFact( addressFact );
-        address2.set("id", "100002");
-        address2.set("customer_id", "1001");
-        address2.set("street", "11 Post Dr.");
+        PrototypeFactInstance address2 = addressFact.newInstance();
+        address2.put("id", "100002");
+        address2.put("customer_id", "1001");
+        address2.put("street", "11 Post Dr.");
         ksession.insert( address2 );
         ksession.fireAllRules();
 
@@ -592,7 +590,7 @@ public class FactTemplateTest {
 
     @Test
     public void testRetract() {
-        Prototype personFact = prototype( "org.drools.Person" );
+        PrototypeFact personFact = prototype( "org.drools.Person" ).asFact();
         PrototypeVariable markV = variable(personFact, "m");
 
         Rule rule = rule( "alpha" )
@@ -610,9 +608,9 @@ public class FactTemplateTest {
         KieSession ksession = kieBase.newKieSession();
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
-        Fact mark = createMapBasedFact(personFact);
-        mark.set( "name", "Mark" );
-        mark.set( "age", 40 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 40 );
 
         FactHandle fh = ksession.insert( mark );
         assertThat(ksession.fireAllRules()).isEqualTo(0);
@@ -624,7 +622,7 @@ public class FactTemplateTest {
     @Test
     public void testUndefinedOnAlpha() {
         // DROOLS-7192
-        Prototype prototype = prototype( "org.X" );
+        PrototypeFact prototype = prototype( "org.X" ).asFact();
 
         PrototypeVariable var1 = variable( prototype );
 
@@ -639,20 +637,20 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact f1 = createMapBasedFact( prototype );
-        f1.set( "j", 2 );
+        PrototypeFactInstance f1 = prototype.newInstance();
+        f1.put("j", 2 );
 
         ksession.insert(f1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f2 = createMapBasedFact( prototype );
-        f2.set( "i", 3 );
+        PrototypeFactInstance f2 = prototype.newInstance();
+        f2.put("i", 3 );
 
         ksession.insert(f2);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f3 = createMapBasedFact( prototype );
-        f3.set( "i", null );
+        PrototypeFactInstance f3 = prototype.newInstance();
+        f3.put("i", null );
 
         ksession.insert(f3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
@@ -661,7 +659,7 @@ public class FactTemplateTest {
     @Test
     public void testUndefinedOnBeta() {
         // DROOLS-7192
-        Prototype prototype = prototype( "org.X" );
+        PrototypeFact prototype = prototype( "org.X" ).asFact();
 
         PrototypeVariable var1 = variable( prototype );
         PrototypeVariable var2 = variable( prototype );
@@ -679,20 +677,20 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact f1 = createMapBasedFact( prototype );
-        f1.set( "custom.expected_index", 2 );
+        PrototypeFactInstance f1 = prototype.newInstance();
+        f1.put("custom.expected_index", 2 );
 
         ksession.insert(f1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f2 = createMapBasedFact( prototype );
-        f2.set( "i", 3 );
+        PrototypeFactInstance f2 = prototype.newInstance();
+        f2.put("i", 3 );
 
         ksession.insert(f2);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f3 = createMapBasedFact( prototype );
-        f3.set( "i", 2 );
+        PrototypeFactInstance f3 = prototype.newInstance();
+        f3.put("i", 2 );
 
         ksession.insert(f3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
@@ -701,7 +699,7 @@ public class FactTemplateTest {
     @Test
     public void testArrayAccess() {
         // DROOLS-7194
-        Prototype prototype = prototype( "org.X" );
+        PrototypeFact prototype = prototype( "org.X" ).asFact();
 
         PrototypeVariable var1 = variable( prototype );
 
@@ -716,18 +714,18 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact f1 = createMapBasedFact( prototype );
-        f1.set("i", List.of(3));
+        PrototypeFactInstance f1 = prototype.newInstance();
+        f1.put("i", List.of(3));
         ksession.insert(f1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f2 = createMapBasedFact( prototype );
-        f2.set( "i", Arrays.asList(1, 3, 5) );
+        PrototypeFactInstance f2 = prototype.newInstance();
+        f2.put("i", Arrays.asList(1, 3, 5) );
         ksession.insert(f2);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
-        Fact f3 = createMapBasedFact( prototype );
-        f3.set( "i", new int[] {1, 3, 5} );
+        PrototypeFactInstance f3 = prototype.newInstance();
+        f3.put("i", new int[] {1, 3, 5} );
         ksession.insert(f3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
@@ -735,7 +733,7 @@ public class FactTemplateTest {
     @Test
     public void testArrayAccessWithOr() {
         // DROOLS-7194
-        Prototype prototype = prototype( "org.X" );
+        PrototypeFact prototype = prototype( "org.X" ).asFact();
 
         PrototypeVariable var1 = variable( prototype );
 
@@ -750,18 +748,18 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact f1 = createMapBasedFact( prototype );
-        f1.set("i", List.of(3));
+        PrototypeFactInstance f1 = prototype.newInstance();
+        f1.put("i", List.of(3));
         ksession.insert(f1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f2 = createMapBasedFact( prototype );
-        f2.set( "i", Arrays.asList(1, 3, 5) );
+        PrototypeFactInstance f2 = prototype.newInstance();
+        f2.put("i", Arrays.asList(1, 3, 5) );
         ksession.insert(f2);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
-        Fact f3 = createMapBasedFact( prototype );
-        f3.set( "i", new int[] {1, 5, 3} );
+        PrototypeFactInstance f3 = prototype.newInstance();
+        f3.put("i", new int[] {1, 5, 3} );
         ksession.insert(f3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
@@ -769,7 +767,7 @@ public class FactTemplateTest {
     @Test
     public void testInnerArrayAccess() {
         // DROOLS-7194
-        Prototype prototype = prototype( "org.X" );
+        PrototypeFact prototype = prototype( "org.X" ).asFact();
 
         PrototypeVariable var1 = variable( prototype );
 
@@ -784,18 +782,18 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact f1 = createMapBasedFact( prototype );
-        f1.set("i", List.of(Map.of("a", 3)));
+        PrototypeFactInstance f1 = prototype.newInstance();
+        f1.put("i", List.of(Map.of("a", 3)));
         ksession.insert(f1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f2 = createMapBasedFact( prototype );
-        f2.set( "i", Arrays.asList(Map.of("a", 1), Map.of("b", 3), Map.of("c", 5)) );
+        PrototypeFactInstance f2 = prototype.newInstance();
+        f2.put("i", Arrays.asList(Map.of("a", 1), Map.of("b", 3), Map.of("c", 5)) );
         ksession.insert(f2);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact f3 = createMapBasedFact( prototype );
-        f3.set( "i", Arrays.asList(Map.of("c", 1), Map.of("a", 3), Map.of("b", 5)) );
+        PrototypeFactInstance f3 = prototype.newInstance();
+        f3.put("i", Arrays.asList(Map.of("c", 1), Map.of("a", 3), Map.of("b", 5)) );
         ksession.insert(f3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
@@ -805,7 +803,7 @@ public class FactTemplateTest {
         // DROOLS-7223
         Result result = new Result();
 
-        Prototype stockTickPrototype = prototype( "org.drools.StockTick" );
+        PrototypeEvent stockTickPrototype = prototype("org.drools.StockTick" ).asEvent();
 
         PrototypeVariable tick1Var = variable( stockTickPrototype );
         PrototypeVariable tick2Var = variable( stockTickPrototype );
@@ -829,39 +827,39 @@ public class FactTemplateTest {
         KieSession ksession = kieBase.newKieSession(conf, null);
         SessionPseudoClock clock = ksession.getSessionClock();
 
-        Event tick1 = createMapBasedEvent( stockTickPrototype );
-        tick1.set( "name", "RedHat" );
-        tick1.set( "value", 10 );
+        PrototypeEventInstance tick1 = stockTickPrototype.newInstance();
+        tick1.put("name", "RedHat" );
+        tick1.put("value", 10 );
         ksession.insert(tick1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
         clock.advanceTime( 3, TimeUnit.SECONDS );
 
-        Event tick2 = createMapBasedEvent( stockTickPrototype );
-        tick2.set( "name", "RedHat" );
-        tick2.set( "value", 15 );
+        PrototypeEventInstance tick2 = stockTickPrototype.newInstance();
+        tick2.put("name", "RedHat" );
+        tick2.put("value", 15 );
         ksession.insert(tick2);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
         clock.advanceTime( 3, TimeUnit.SECONDS );
 
-        Event tick3 = createMapBasedEvent( stockTickPrototype );
-        tick3.set( "name", "test" );
-        tick3.set( "value", 12 );
+        PrototypeEventInstance tick3 = stockTickPrototype.newInstance();
+        tick3.put("name", "test" );
+        tick3.put("value", 12 );
         ksession.insert(tick3);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Event tick4 = createMapBasedEvent( stockTickPrototype );
-        tick4.set( "name", "RedHat" );
-        tick4.set( "value", 9 );
+        PrototypeEventInstance tick4 = stockTickPrototype.newInstance();
+        tick4.put("name", "RedHat" );
+        tick4.put("value", 9 );
         ksession.insert(tick4);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
         clock.advanceTime( 3, TimeUnit.SECONDS );
 
-        Event tick5 = createMapBasedEvent( stockTickPrototype );
-        tick5.set( "name", "RedHat" );
-        tick5.set( "value", 14 );
+        PrototypeEventInstance tick5 = stockTickPrototype.newInstance();
+        tick5.put("name", "RedHat" );
+        tick5.put("value", 14 );
         ksession.insert(tick5);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
@@ -869,9 +867,9 @@ public class FactTemplateTest {
 
         clock.advanceTime( 6, TimeUnit.SECONDS );
 
-        Event tick6 = createMapBasedEvent( stockTickPrototype );
-        tick6.set( "name", "RedHat" );
-        tick6.set( "value", 13 );
+        PrototypeEventInstance tick6 = stockTickPrototype.newInstance();
+        tick6.put("name", "RedHat" );
+        tick6.put("value", 13 );
         ksession.insert(tick6);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
@@ -882,10 +880,10 @@ public class FactTemplateTest {
     public void testUniqueEventInTimeWindow() {
         Result result = new Result();
 
-        Prototype stockTickPrototype = prototype( "org.drools.StockTick" );
+        PrototypeEvent stockTickPrototype = prototype( "org.drools.StockTick" ).asEvent();
         PrototypeVariable tick1Var = variable( stockTickPrototype );
 
-        Prototype controlPrototype = prototype( "org.drools.ControlEvent" );
+        PrototypeEvent controlPrototype = prototype( "org.drools.ControlEvent" ).asEvent();
         PrototypeVariable controlVar = variable( controlPrototype );
 
         Rule rule = rule( "stock" )
@@ -893,8 +891,8 @@ public class FactTemplateTest {
                         protoPattern(tick1Var).expr( "value", Index.ConstraintType.GREATER_THAN, 2 ),
                         not( protoPattern(controlVar).expr( "name", Index.ConstraintType.EQUAL, tick1Var, "name" ) ),
                         on(tick1Var).execute((drools, t1) -> {
-                            Event controlEvent = createMapBasedEvent( controlPrototype ).withExpiration(10, TimeUnit.SECONDS);
-                            controlEvent.set( "name", t1.get( "name" ) );
+                            PrototypeEventInstance controlEvent = controlPrototype.newInstance().withExpiration(10, TimeUnit.SECONDS);
+                            controlEvent.put("name", t1.get("name" ) );
                             drools.insert(controlEvent);
                             result.setValue( t1.get( "name" ) + " worth " + t1.get( "value" ));
                         })
@@ -916,9 +914,9 @@ public class FactTemplateTest {
         KieSession ksession = kieBase.newKieSession(conf, null);
         SessionPseudoClock clock = ksession.getSessionClock();
 
-        Event tick1 = createMapBasedEvent( stockTickPrototype );
-        tick1.set( "name", "RedHat" );
-        tick1.set( "value", 10 );
+        PrototypeEventInstance tick1 = stockTickPrototype.newInstance();
+        tick1.put("name", "RedHat" );
+        tick1.put("value", 10 );
         ksession.insert(tick1);
         assertThat(ksession.fireAllRules()).isEqualTo(2);
 
@@ -927,15 +925,15 @@ public class FactTemplateTest {
 
         clock.advanceTime( 3, TimeUnit.SECONDS );
 
-        Event tick2 = createMapBasedEvent( stockTickPrototype );
-        tick2.set( "name", "RedHat" );
-        tick2.set( "value", 12 );
+        PrototypeEventInstance tick2 = stockTickPrototype.newInstance();
+        tick2.put("name", "RedHat" );
+        tick2.put("value", 12 );
         ksession.insert(tick2);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
-        Event tickTest = createMapBasedEvent( stockTickPrototype );
-        tickTest.set( "name", "test" );
-        tickTest.set( "value", 42 );
+        PrototypeEventInstance tickTest = stockTickPrototype.newInstance();
+        tickTest.put("name", "test" );
+        tickTest.put("value", 42 );
         FactHandle fhTest = ksession.insert(tickTest);
         assertThat(ksession.fireAllRules()).isEqualTo(2);
 
@@ -944,18 +942,18 @@ public class FactTemplateTest {
 
         clock.advanceTime( 4, TimeUnit.SECONDS );
 
-        Event tick3 = createMapBasedEvent( stockTickPrototype );
-        tick3.set( "name", "RedHat" );
-        tick3.set( "value", 14 );
+        PrototypeEventInstance tick3 = stockTickPrototype.newInstance();
+        tick3.put("name", "RedHat" );
+        tick3.put("value", 14 );
         ksession.insert(tick3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
         assertThat(result.getValue()).isNull();
 
         clock.advanceTime( 5, TimeUnit.SECONDS );
 
-        Event tick4 = createMapBasedEvent( stockTickPrototype );
-        tick4.set( "name", "RedHat" );
-        tick4.set( "value", 15 );
+        PrototypeEventInstance tick4 = stockTickPrototype.newInstance();
+        tick4.put("name", "RedHat" );
+        tick4.put("value", 15 );
         ksession.insert(tick4);
         assertThat(ksession.fireAllRules()).isEqualTo(2);
 
@@ -967,7 +965,7 @@ public class FactTemplateTest {
         // DROOLS-7244
         Result result = new Result();
 
-        Prototype controlPrototype = prototype( "org.drools.ControlEvent" );
+        PrototypeEvent controlPrototype = prototype( "org.drools.ControlEvent" ).asEvent();
         PrototypeVariable controlVar1 = variable( controlPrototype );
         PrototypeVariable controlVar2 = variable( controlPrototype );
 
@@ -990,8 +988,8 @@ public class FactTemplateTest {
         KieSession ksession = kieBase.newKieSession(conf, null);
         SessionPseudoClock clock = ksession.getSessionClock();
 
-        Event tick1 = createMapBasedEvent( controlPrototype );
-        tick1.set( "name", "start_R" );
+        PrototypeEventInstance tick1 = controlPrototype.newInstance();
+        tick1.put("name", "start_R" );
         ksession.insert(tick1);
 
         ksession.fireAllRules();
@@ -1011,10 +1009,10 @@ public class FactTemplateTest {
         // DROOLS-7244
         Result result = new Result();
 
-        Prototype stockTickPrototype = prototype( "org.drools.StockTick" );
+        PrototypeEvent stockTickPrototype = prototype( "org.drools.StockTick" ).asEvent();
         PrototypeVariable tick1Var = variable( stockTickPrototype );
 
-        Prototype controlPrototype = prototype( "org.drools.ControlEvent" );
+        PrototypeEvent controlPrototype = prototype( "org.drools.ControlEvent" ).asEvent();
         PrototypeVariable controlVar1 = variable( controlPrototype );
         PrototypeVariable controlVar2 = variable( controlPrototype );
 
@@ -1023,9 +1021,9 @@ public class FactTemplateTest {
                         protoPattern(tick1Var).expr( "value", Index.ConstraintType.GREATER_THAN, 10 ),
                         not( protoPattern(controlVar1).expr( "name", Index.ConstraintType.EQUAL, "R1" ) ),
                         on(tick1Var).execute((drools, t1) -> {
-                            Event controlEvent = createMapBasedEvent( controlPrototype ).withExpiration(10, TimeUnit.SECONDS);
-                            controlEvent.set( "name", "R1" );
-                            controlEvent.set( "event", t1 );
+                            PrototypeEventInstance controlEvent = controlPrototype.newInstance().withExpiration(10, TimeUnit.SECONDS);
+                            controlEvent.put("name", "R1" );
+                            controlEvent.put("event", t1 );
                             System.out.println("insert: " + controlEvent);
                             drools.insert(controlEvent);
                         })
@@ -1036,9 +1034,9 @@ public class FactTemplateTest {
                         protoPattern(tick1Var).expr( "value", Index.ConstraintType.LESS_THAN, 5 ),
                         not( protoPattern(controlVar1).expr( "name", Index.ConstraintType.EQUAL, "R2" ) ),
                         on(tick1Var).execute((drools, t1) -> {
-                            Event controlEvent = createMapBasedEvent( controlPrototype ).withExpiration(10, TimeUnit.SECONDS);
-                            controlEvent.set( "name", "R2" );
-                            controlEvent.set( "event", t1 );
+                            PrototypeEventInstance controlEvent = controlPrototype.newInstance().withExpiration(10, TimeUnit.SECONDS);
+                            controlEvent.put("name", "R2" );
+                            controlEvent.put("event", t1 );
                             System.out.println("insert: " + controlEvent);
                             drools.insert(controlEvent);
                         })
@@ -1053,8 +1051,8 @@ public class FactTemplateTest {
                                 accFunction(org.drools.core.base.accumulators.CountAccumulateFunction::new).as(resultCount)),
                         pattern(resultCount).expr(count -> count > 0),
                         on(resultCount).execute((drools, count) -> {
-                            Event controlEvent = createMapBasedEvent( controlPrototype ).withExpiration(10, TimeUnit.SECONDS);
-                            controlEvent.set( "name", "start_R" );
+                            PrototypeEventInstance controlEvent = controlPrototype.newInstance().withExpiration(10, TimeUnit.SECONDS);
+                            controlEvent.put("name", "start_R" );
                             System.out.println("insert: " + controlEvent);
                             drools.insert(controlEvent);
                         })
@@ -1067,8 +1065,8 @@ public class FactTemplateTest {
                                 accFunction(org.drools.core.base.accumulators.CountAccumulateFunction::new).as(resultCount)),
                         pattern(resultCount).expr(count -> count == 2),
                         on(resultCount).execute((drools, count) -> {
-                            Event controlEvent = createMapBasedEvent( controlPrototype ).withExpiration(10, TimeUnit.SECONDS);
-                            controlEvent.set( "name", "end_R" );
+                            PrototypeEventInstance controlEvent = controlPrototype.newInstance().withExpiration(10, TimeUnit.SECONDS);
+                            controlEvent.put("name", "end_R" );
                             System.out.println("insert: " + controlEvent);
                             drools.insert(controlEvent);
                         })
@@ -1114,9 +1112,9 @@ public class FactTemplateTest {
         KieSession ksession = kieBase.newKieSession(conf, null);
         SessionPseudoClock clock = ksession.getSessionClock();
 
-        Event tick1 = createMapBasedEvent( stockTickPrototype );
-        tick1.set( "name", "RedHat" );
-        tick1.set( "value", 7 );
+        PrototypeEventInstance tick1 = stockTickPrototype.newInstance();
+        tick1.put("name", "RedHat" );
+        tick1.put("value", 7 );
         ksession.insert(tick1);
 
         ksession.fireAllRules();
@@ -1124,9 +1122,9 @@ public class FactTemplateTest {
 
         clock.advanceTime( 1, TimeUnit.SECONDS );
 
-        Event tick2 = createMapBasedEvent( stockTickPrototype );
-        tick2.set( "name", "RedHat" );
-        tick2.set( "value", 17 );
+        PrototypeEventInstance tick2 = stockTickPrototype.newInstance();
+        tick2.put("name", "RedHat" );
+        tick2.put("value", 17 );
         ksession.insert(tick2);
 
         ksession.fireAllRules();
@@ -1134,9 +1132,9 @@ public class FactTemplateTest {
 
         clock.advanceTime( 9, TimeUnit.SECONDS );
 
-        Event tick3 = createMapBasedEvent( stockTickPrototype );
-        tick3.set( "name", "RedHat" );
-        tick3.set( "value", 3 );
+        PrototypeEventInstance tick3 = stockTickPrototype.newInstance();
+        tick3.put("name", "RedHat" );
+        tick3.put("value", 3 );
         ksession.insert(tick3);
 
         ksession.fireAllRules();
@@ -1144,9 +1142,9 @@ public class FactTemplateTest {
 
         clock.advanceTime( 5, TimeUnit.SECONDS );
 
-        Event tick4 = createMapBasedEvent( stockTickPrototype );
-        tick4.set( "name", "RedHat" );
-        tick4.set( "value", 2 );
+        PrototypeEventInstance tick4 = stockTickPrototype.newInstance();
+        tick4.put("name", "RedHat" );
+        tick4.put("value", 2 );
         ksession.insert(tick4);
 
         ksession.fireAllRules();
@@ -1166,7 +1164,7 @@ public class FactTemplateTest {
     @Test
     public void testListContains() {
         // DROOLS-7259
-        Prototype prototype = prototype( "org.X" );
+        PrototypeFact prototype = prototype( "org.X" ).asFact();
         PrototypeVariable prototypeV = variable(prototype);
 
         Rule rule = rule( "alpha" )
@@ -1183,16 +1181,16 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact fact1 = createMapBasedFact(prototype);
-        fact1.set( "name", "fact1" );
-        fact1.set( "ids", Arrays.asList(2, 4) );
+        PrototypeFactInstance fact1 = prototype.newInstance();
+        fact1.put("name", "fact1" );
+        fact1.put("ids", Arrays.asList(2, 4) );
         ksession.insert(fact1);
 
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact fact2 = createMapBasedFact(prototype);
-        fact2.set( "name", "fact2" );
-        fact2.set( "ids", Arrays.asList(1, 3, 5) );
+        PrototypeFactInstance fact2 = prototype.newInstance();
+        fact2.put("name", "fact2" );
+        fact2.put("ids", Arrays.asList(1, 3, 5) );
         ksession.insert(fact2);
 
         assertThat(ksession.fireAllRules()).isEqualTo(1);
@@ -1205,10 +1203,10 @@ public class FactTemplateTest {
     public void testCollectUniqueEventsAfterTimeWindow() {
         Result result = new Result();
 
-        Prototype stockTickPrototype = prototype( "org.drools.StockTick" );
+        PrototypeEvent stockTickPrototype = prototype( "org.drools.StockTick" ).asEvent();
         PrototypeVariable tick1Var = variable( stockTickPrototype );
 
-        Prototype controlPrototype = prototype( "org.drools.ControlEvent" );
+        PrototypeEvent controlPrototype = prototype( "org.drools.ControlEvent" ).asEvent();
         PrototypeVariable controlVar1 = variable( controlPrototype );
         PrototypeVariable controlVar2 = variable( controlPrototype );
         PrototypeVariable controlVar3 = variable( controlPrototype );
@@ -1220,10 +1218,10 @@ public class FactTemplateTest {
                         protoPattern(tick1Var).expr( "value", Index.ConstraintType.GREATER_THAN, 2 ),
                         not( protoPattern(controlVar1).expr( "rule_name", Index.ConstraintType.EQUAL, "stock" ).expr( "name", Index.ConstraintType.EQUAL, tick1Var, "name" ) ),
                         on(tick1Var).execute((drools, t1) -> {
-                            Event controlEvent = createMapBasedEvent( controlPrototype );
-                            controlEvent.set( "name", t1.get( "name" ) );
-                            controlEvent.set( "event", t1 );
-                            controlEvent.set( "rule_name", "stock" );
+                            PrototypeEventInstance controlEvent = controlPrototype.newInstance();
+                            controlEvent.put("name", t1.get("name" ) );
+                            controlEvent.put("event", t1 );
+                            controlEvent.put("rule_name", "stock" );
                             drools.insert(controlEvent);
                             drools.delete(t1);
                         })
@@ -1234,12 +1232,12 @@ public class FactTemplateTest {
                         protoPattern(controlVar1).expr( "rule_name", Index.ConstraintType.EQUAL, "stock" ),
                         not( protoPattern(controlVar2).expr( "end_once_after", Index.ConstraintType.EQUAL, "stock" ) ),
                         on(controlVar1).execute((drools, c1) -> {
-                            Event startControlEvent = createMapBasedEvent( controlPrototype ).withExpiration(10, TimeUnit.SECONDS);
-                            startControlEvent.set( "start_once_after", c1.get( "rule_name" ) );
+                            PrototypeEventInstance startControlEvent = controlPrototype.newInstance().withExpiration(10, TimeUnit.SECONDS);
+                            startControlEvent.put("start_once_after", c1.get("rule_name" ) );
                             drools.insert(startControlEvent);
 
-                            Event endControlEvent = createMapBasedEvent( controlPrototype );
-                            endControlEvent.set( "end_once_after", c1.get( "rule_name" ) );
+                            PrototypeEventInstance endControlEvent = controlPrototype.newInstance();
+                            endControlEvent.put("end_once_after", c1.get("rule_name" ) );
                             drools.insert(endControlEvent);
                         })
                 );
@@ -1252,7 +1250,7 @@ public class FactTemplateTest {
                                 accFunction(org.drools.core.base.accumulators.CollectListAccumulateFunction::new, controlVar3).as(resultsVar)),
                         on(controlVar1, resultsVar).execute((drools, c1, results) -> {
                             drools.delete(c1);
-                            result.setValue(results.stream().peek(drools::delete).map(r -> ((PrototypeFact) r).get("event")).collect(Collectors.toList()));
+                            result.setValue(results.stream().peek(drools::delete).map(r -> ((PrototypeFactInstance) r).get("event")).collect(Collectors.toList()));
                         })
                 );
 
@@ -1272,33 +1270,33 @@ public class FactTemplateTest {
         KieSession ksession = kieBase.newKieSession(conf, null);
         SessionPseudoClock clock = ksession.getSessionClock();
 
-        Event tick1 = createMapBasedEvent( stockTickPrototype );
-        tick1.set( "name", "RedHat" );
-        tick1.set( "value", 10 );
+        PrototypeEventInstance tick1 = stockTickPrototype.newInstance();
+        tick1.put("name", "RedHat" );
+        tick1.put("value", 10 );
         ksession.insert(tick1);
         assertThat(ksession.fireAllRules()).isEqualTo(2);
 
         clock.advanceTime( 3, TimeUnit.SECONDS );
 
-        Event tick2 = createMapBasedEvent( stockTickPrototype );
-        tick2.set( "name", "RedHat" );
-        tick2.set( "value", 12 );
+        PrototypeEventInstance tick2 = stockTickPrototype.newInstance();
+        tick2.put("name", "RedHat" );
+        tick2.put("value", 12 );
         ksession.insert(tick2);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
         assertThat(result.getValue()).isNull();
 
-        Event tickTest = createMapBasedEvent( stockTickPrototype );
-        tickTest.set( "name", "test" );
-        tickTest.set( "value", 42 );
+        PrototypeEventInstance tickTest = stockTickPrototype.newInstance();
+        tickTest.put("name", "test" );
+        tickTest.put("value", 42 );
         ksession.insert(tickTest);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
         assertThat(result.getValue()).isNull();
 
         clock.advanceTime( 4, TimeUnit.SECONDS );
 
-        Event tick3 = createMapBasedEvent( stockTickPrototype );
-        tick3.set( "name", "RedHat" );
-        tick3.set( "value", 14 );
+        PrototypeEventInstance tick3 = stockTickPrototype.newInstance();
+        tick3.put("name", "RedHat" );
+        tick3.put("value", 14 );
         ksession.insert(tick3);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
         assertThat(result.getValue()).isNull();
@@ -1307,9 +1305,9 @@ public class FactTemplateTest {
 
         assertThat(ksession.fireAllRules()).isEqualTo(1);
 
-        List<PrototypeFact> events = (List<PrototypeFact>) result.getValue();
+        List<PrototypeFactInstance> events = (List<PrototypeFactInstance>) result.getValue();
         assertThat(events).hasSize(2);
-        for (PrototypeFact event : events) {
+        for (PrototypeFactInstance event : events) {
             if (event.get("name").equals("RedHat")) {
                 assertThat(event.get("value")).isEqualTo(10);
             } else if (event.get("name").equals("test")) {
@@ -1322,7 +1320,7 @@ public class FactTemplateTest {
 
     @Test
     public void testAddOnDifferentPrototypes() {
-        Prototype testPrototype = prototype( "test" );
+        PrototypeFact testPrototype = prototype( "test" ).asFact();
         PrototypeVariable test1V = variable(testPrototype);
         PrototypeVariable test2V = variable(testPrototype);
         PrototypeVariable test3V = variable(testPrototype);
@@ -1343,23 +1341,23 @@ public class FactTemplateTest {
         KieBase kieBase = KieBaseBuilder.createKieBaseFromModel( model );
         KieSession ksession = kieBase.newKieSession();
 
-        Fact testFact1 = createMapBasedFact(testPrototype);
-        testFact1.set( "i", 1 );
+        PrototypeFactInstance testFact1 = testPrototype.newInstance();
+        testFact1.put("i", 1 );
         ksession.insert(testFact1);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact testFact2 = createMapBasedFact(testPrototype);
-        testFact2.set( "i", 2 );
+        PrototypeFactInstance testFact2 = testPrototype.newInstance();
+        testFact2.put("i", 2 );
         ksession.insert(testFact2);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact testFact3 = createMapBasedFact(testPrototype);
-        testFact3.set( "i", 3 );
+        PrototypeFactInstance testFact3 = testPrototype.newInstance();
+        testFact3.put("i", 3 );
         ksession.insert(testFact3);
         assertThat(ksession.fireAllRules()).isEqualTo(0);
 
-        Fact testFact4 = createMapBasedFact(testPrototype);
-        testFact4.set( "i", 4 );
+        PrototypeFactInstance testFact4 = testPrototype.newInstance();
+        testFact4.put("i", 4 );
         ksession.insert(testFact4);
         assertThat(ksession.fireAllRules()).isEqualTo(1);
     }
@@ -1367,7 +1365,7 @@ public class FactTemplateTest {
     @Test
     public void testComparisonWithDifferentNumericTypes() {
         // DROOLS-7332
-        Prototype personFact = prototype( "org.drools.FactPerson", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.FactPerson" ).withField("name").withField("age").asFact();
 
         PrototypeVariable markV = variable( personFact );
 
@@ -1383,11 +1381,11 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        assertThat(hasFactTemplateObjectType(ksession, "FactPerson")).isTrue();
+        assertThat(hasPrototypeObjectType(ksession, "org.drools.FactPerson")).isTrue();
 
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", 18 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 18 );
 
         ksession.insert( mark );
 
@@ -1400,7 +1398,7 @@ public class FactTemplateTest {
     @Test
     public void testEqualityWithDifferentNumericTypes() {
         // DROOLS-7332
-        Prototype personFact = prototype( "org.drools.FactPerson", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.FactPerson" ).withField("name").withField("age").asFact();
 
         PrototypeVariable markV = variable( personFact );
 
@@ -1416,11 +1414,11 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        assertThat(hasFactTemplateObjectType(ksession, "FactPerson")).isTrue();
+        assertThat(hasPrototypeObjectType(ksession, "org.drools.FactPerson")).isTrue();
 
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", 18 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 18 );
 
         ksession.insert( mark );
 
@@ -1433,7 +1431,7 @@ public class FactTemplateTest {
     @Test
     public void bigDecimalEqualityWithDifferentScale_shouldBeEqual() {
         // DROOLS-7332
-        Prototype personFact = prototype( "org.drools.FactPerson", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.FactPerson" ).withField("name").withField("age").asFact();
 
         PrototypeVariable markV = variable( personFact );
 
@@ -1449,11 +1447,11 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        assertThat(hasFactTemplateObjectType(ksession, "FactPerson")).isTrue();
+        assertThat(hasPrototypeObjectType(ksession, "org.drools.FactPerson")).isTrue();
 
-        Fact mark = createMapBasedFact( personFact );
-        mark.set( "name", "Mark" );
-        mark.set( "age", new BigDecimal("18.00") );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", new BigDecimal("18.00") );
 
         ksession.insert( mark );
 
@@ -1466,7 +1464,7 @@ public class FactTemplateTest {
     @Test
     public void testMixFieldNameAndPrototypeExpr() {
         // DROOLS-7517
-        Prototype personFact = prototype( "org.drools.FactPerson", "name", "age" );
+        PrototypeFact personFact = prototype( "org.drools.FactPerson" ).withField("name").withField("age").asFact();
 
         PrototypeVariable markV = variable( personFact );
 
@@ -1502,9 +1500,9 @@ public class FactTemplateTest {
 
         KieSession ksession = kieBase.newKieSession();
 
-        Fact mark = createMapBasedFact(personFact);
-        mark.set( "name", "Mark" );
-        mark.set( "age", 40 );
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 40 );
 
         FactHandle fh = ksession.insert( mark );
         assertThat(ksession.fireAllRules()).isEqualTo(2);
@@ -1522,7 +1520,7 @@ public class FactTemplateTest {
         }
 
         @Override
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
             return prototype.getFieldValueExtractor(fieldName)::apply;
         }
 
diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/PrototypesAllowedTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/PrototypesAllowedTest.java
new file mode 100644
index 0000000000..28c257ea97
--- /dev/null
+++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/PrototypesAllowedTest.java
@@ -0,0 +1,215 @@
+/**
+ * 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.drools.model.codegen.execmodel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.drools.model.Index;
+import org.drools.model.Model;
+import org.drools.model.Rule;
+import org.drools.model.codegen.ExecutableModelProject;
+import org.drools.model.impl.ModelImpl;
+import org.drools.model.prototype.PrototypeVariable;
+import org.drools.modelcompiler.KieBaseBuilder;
+import org.junit.Test;
+import org.kie.api.KieBase;
+import org.kie.api.conf.PrototypesOption;
+import org.kie.api.io.ResourceType;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
+import org.kie.api.runtime.KieSession;
+import org.kie.internal.utils.KieHelper;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.drools.model.DSL.on;
+import static org.drools.model.PatternDSL.rule;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
+
+public class PrototypesAllowedTest {
+
+    @Test
+    public void testModel() {
+        PrototypeVariable personV = variable(prototype( "Person" ).asFact());
+
+        Rule rule = rule("adult" )
+                .build(
+                        protoPattern(personV)
+                                .expr("age", Index.ConstraintType.GREATER_OR_EQUAL, 18 ),
+                        on(personV).execute(p -> p.put("adult", true))
+                );
+
+        Model model = new ModelImpl().addRule(rule );
+        KieBase kieBase = KieBaseBuilder.createKieBaseFromModel(model );
+
+        KieSession ksession = kieBase.newKieSession();
+
+        PrototypeFact personFact = prototype("Person").asFact();
+
+        PrototypeFactInstance sofia = personFact.newInstance();
+        sofia.put("name", "Sofia" );
+        sofia.put("age", 12 );
+
+        ksession.insert(sofia);
+        assertThat(ksession.fireAllRules()).isEqualTo(0);
+        assertThat(sofia.get("adult")).isNull();
+
+        PrototypeFactInstance mario = personFact.newInstance();
+        mario.put("name", "Mario" );
+        mario.put("age", 49 );
+
+        ksession.insert(mario);
+        assertThat(ksession.fireAllRules()).isEqualTo(1);
+        assertThat(mario.get("adult")).isEqualTo(true);
+    }
+
+    @Test
+    public void testPrototypeDrl() {
+        String str =
+                """
+                global java.util.List results
+                rule Adult when
+                  $p : Person( age >= 18 )
+                then
+                  $p.adult = true;
+                  results.add($p.name);
+                end
+                """;
+
+        KieSession ksession = new KieHelper()
+                .addContent(str, ResourceType.DRL)
+                .build(ExecutableModelProject.class, PrototypesOption.ALLOWED)
+                .newKieSession();
+
+        List<String> results = new ArrayList<>();
+        ksession.setGlobal("results", results);
+
+        PrototypeFact personFact = prototype("Person").asFact();
+
+        PrototypeFactInstance sofia = personFact.newInstance();
+        sofia.put("name", "Sofia" );
+        sofia.put("age", 12 );
+
+        ksession.insert(sofia);
+        assertThat(ksession.fireAllRules()).isEqualTo(0);
+        assertThat(sofia.get("adult")).isNull();
+
+        PrototypeFactInstance mario = personFact.newInstance();
+        mario.put("name", "Mario" );
+        mario.put("age", 49 );
+
+        ksession.insert(mario);
+        assertThat(ksession.fireAllRules()).isEqualTo(1);
+        assertThat(mario.get("adult")).isEqualTo(true);
+
+        assertThat(results.size()).isEqualTo(1);
+        assertThat(results.get(0)).isEqualTo("Mario");
+    }
+
+    @Test
+    public void testJoin() {
+        String str =
+                """
+                package org.drools.prototype;
+                
+                rule "R1"
+                when
+                  $r : Result()
+                  $p : Person(age >= 18)
+                then
+                  $r.value = $p.name + " can drink";
+                end
+               
+                rule "R2"
+                when
+                  $r : Result()
+                  $p : Person(age < 18)
+                then
+                  $r.value = $p.name + " can NOT drink";
+                end
+                """;
+
+        KieSession ksession = new KieHelper()
+                .addContent(str, ResourceType.DRL)
+                .build(ExecutableModelProject.class, PrototypesOption.ALLOWED)
+                .newKieSession();
+
+        PrototypeFact personFact = prototype("Person").asFact();
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 17 );
+        ksession.insert(mark);
+
+        PrototypeFact resultFact = prototype("Result").asFact();
+        PrototypeFactInstance result = resultFact.newInstance();
+        ksession.insert(result);
+
+        assertThat(ksession.fireAllRules()).isEqualTo(1);
+        assertEquals("Mark can NOT drink", result.get("value"));
+    }
+
+
+    @Test
+    public void testAccessMapFieldsInMvel() {
+        String str =
+                """
+                dialect "mvel"
+                import java.util.Map
+                global java.util.List results
+                rule Adult when
+                  $p : Map( age >= 18 )
+                then
+                  $p.adult = true;
+                  results.add($p.name);
+                end
+                """;
+
+        KieSession ksession = new KieHelper()
+                .addContent(str, ResourceType.DRL)
+                .build(ExecutableModelProject.class)
+                .newKieSession();
+
+        List<String> results = new ArrayList<>();
+        ksession.setGlobal("results", results);
+
+        Map<String, Object> sofia = new HashMap<>();
+        sofia.put( "name", "Sofia" );
+        sofia.put( "age", 12 );
+
+        ksession.insert(sofia);
+        assertThat(ksession.fireAllRules()).isEqualTo(0);
+        assertThat(sofia.get("adult")).isNull();
+
+        Map<String, Object> mario = new HashMap<>();
+        mario.put( "name", "Mario" );
+        mario.put( "age", 49 );
+
+        ksession.insert(mario);
+        assertThat(ksession.fireAllRules()).isEqualTo(1);
+        assertThat(mario.get("adult")).isEqualTo(true);
+
+        assertThat(results.size()).isEqualTo(1);
+        assertThat(results.get(0)).isEqualTo("Mario");
+    }
+}
diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/SegmentPrototypeExpressionTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/SegmentPrototypeExpressionTest.java
index f723540d55..383a1a044f 100644
--- a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/SegmentPrototypeExpressionTest.java
+++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/SegmentPrototypeExpressionTest.java
@@ -18,16 +18,15 @@
  */
 package org.drools.model.codegen.execmodel;
 
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeExpression;
-import org.drools.model.PrototypeFact;
+import org.drools.model.prototype.PrototypeExpression;
 import org.junit.Test;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.drools.model.PrototypeDSL.prototype;
-import static org.drools.model.PrototypeExpression.fixedValue;
-import static org.drools.model.PrototypeExpression.prototypeField;
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedFact;
+import static org.drools.model.prototype.PrototypeExpression.fixedValue;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
 
 public class SegmentPrototypeExpressionTest {
 
@@ -36,11 +35,11 @@ public class SegmentPrototypeExpressionTest {
         PrototypeExpression expr1 = prototypeField("fieldA");
         PrototypeExpression expr2 = prototypeField("fieldB").add(prototypeField("fieldC")).sub(fixedValue(1));
 
-        Prototype prototype = prototype("test");
-        PrototypeFact testFact = (PrototypeFact) createMapBasedFact(prototype);
-        testFact.set( "fieldA", 12 );
-        testFact.set( "fieldB", 8 );
-        testFact.set( "fieldC", 5 );
+        PrototypeFact prototype = prototype("test").asFact();
+        PrototypeFactInstance testFact = prototype.newInstance();
+        testFact.put("fieldA", 12 );
+        testFact.put("fieldB", 8 );
+        testFact.put("fieldC", 5 );
 
         assertThat(expr1.asFunction(prototype).apply(testFact)).isEqualTo(expr2.asFunction(prototype).apply(testFact));
         assertThat(expr1.getImpactedFields()).containsExactly("fieldA");
diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
index 29a0e20a66..0332dedb9c 100644
--- a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
+++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
@@ -139,8 +139,8 @@ public class ExpressionTyperTest {
     public void testAssignment() {
         final TypedExpression expected = typedResult("total = total + $cheese.getPrice()", Integer.class);
         final TypedExpression actual = toTypedExpression("total = total + $cheese.price", Object.class,
-                                                         new DeclarationSpec("$cheese", Cheese.class),
-                                                         new DeclarationSpec("total", Integer.class));
+                                                         new TypedDeclarationSpec("$cheese", Cheese.class),
+                                                         new TypedDeclarationSpec("total", Integer.class));
         assertThat(actual).isEqualTo(expected);
     }
 
@@ -173,7 +173,7 @@ public class ExpressionTyperTest {
     @Test
     public void mapAccessExpr2() {
         final TypedExpression expected3 = typedResult("$p.getItems().get(\"type\")", Integer.class, "$p.items[\"type\"]");
-        final TypedExpression actual3 = toTypedExpression("$p.items[\"type\"]", Object.class, new DeclarationSpec("$p", Person.class));
+        final TypedExpression actual3 = toTypedExpression("$p.items[\"type\"]", Object.class, new TypedDeclarationSpec("$p", Person.class));
         assertThat(actual3).isEqualTo(expected3);
     }
 
@@ -181,7 +181,7 @@ public class ExpressionTyperTest {
     public void mapAccessExpr3() {
         final TypedExpression expected = typedResult("$p.getItems().get(1)", Integer.class, "$p.items[1]");
         final TypedExpression actual = toTypedExpression("$p.items[1]", Object.class,
-                                                         new DeclarationSpec("$p", Person.class));
+                                                         new TypedDeclarationSpec("$p", Person.class));
         assertThat(actual).isEqualTo(expected);
     }
 
@@ -189,7 +189,7 @@ public class ExpressionTyperTest {
     public void arrayAccessExprDeclaration() {
         final TypedExpression expected = typedResult("$data.getValues().get(0)", Integer.class, "$data.values[0]");
         final TypedExpression actual = toTypedExpression("$data.values[0]", Object.class,
-                                                         new DeclarationSpec("$data", Data.class));
+                                                         new TypedDeclarationSpec("$data", Data.class));
         assertThat(actual).isEqualTo(expected);
     }
 
@@ -274,9 +274,9 @@ public class ExpressionTyperTest {
         assertThat(typedExpression.getExpression().toString()).isEqualTo(expected);
     }
 
-    private TypedExpression toTypedExpression(String inputExpression, Class<?> patternType, DeclarationSpec... declarations) {
+    private TypedExpression toTypedExpression(String inputExpression, Class<?> patternType, TypedDeclarationSpec... declarations) {
 
-        for(DeclarationSpec d : declarations) {
+        for(TypedDeclarationSpec d : declarations) {
             ruleContext.addDeclaration(d);
         }
         Expression expression = DrlxParseUtil.parseExpression(inputExpression).getExpr();
@@ -294,8 +294,8 @@ public class ExpressionTyperTest {
         return new TypedExpression(resultExpression, classResult, fieldName);
     }
 
-    private DeclarationSpec aPersonDecl(String $mark) {
-        return new DeclarationSpec($mark, Person.class);
+    private TypedDeclarationSpec aPersonDecl(String $mark) {
+        return new TypedDeclarationSpec($mark, Person.class);
     }
 
     private void addInlineCastImport() {
diff --git a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/KiePackagesBuilder.java b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/KiePackagesBuilder.java
index af0d0dd5d9..3189e751f7 100644
--- a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/KiePackagesBuilder.java
+++ b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/KiePackagesBuilder.java
@@ -44,7 +44,6 @@ import org.drools.base.definitions.InternalKnowledgePackage;
 import org.drools.base.definitions.impl.KnowledgePackageImpl;
 import org.drools.base.definitions.rule.impl.QueryImpl;
 import org.drools.base.definitions.rule.impl.RuleImpl;
-import org.drools.base.facttemplates.FactTemplateObjectType;
 import org.drools.base.rule.Accumulate;
 import org.drools.base.rule.AsyncReceive;
 import org.drools.base.rule.AsyncSend;
@@ -100,8 +99,6 @@ import org.drools.model.Global;
 import org.drools.model.GroupByPattern;
 import org.drools.model.Index;
 import org.drools.model.Model;
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeVariable;
 import org.drools.model.Query;
 import org.drools.model.Rule;
 import org.drools.model.SingleConstraint;
@@ -161,7 +158,6 @@ import static org.drools.model.DSL.declarationOf;
 import static org.drools.model.bitmask.BitMaskUtil.calculatePatternMask;
 import static org.drools.model.functions.FunctionUtils.toFunctionN;
 import static org.drools.model.impl.NamesGenerator.generateName;
-import static org.drools.modelcompiler.facttemplate.FactFactory.prototypeToFactTemplate;
 import static org.drools.modelcompiler.util.EvaluationUtil.adaptBitMask;
 import static org.drools.modelcompiler.util.TimerUtil.buildTimerExpression;
 import static org.drools.modelcompiler.util.TypeDeclarationUtil.createTypeDeclaration;
@@ -1204,20 +1200,11 @@ public class KiePackagesBuilder {
     }
 
     ObjectType getObjectType( Variable patternVariable ) {
-        return patternVariable instanceof PrototypeVariable ?
-                getPrototypeObjectType( (( PrototypeVariable ) patternVariable).getPrototype() ) :
+        return patternVariable.isPrototype() ?
+                PrototypeService.get().getPrototypeObjectType( objectTypeCache, packages, this::createKiePackage, patternVariable ) :
                 getClassObjectType( patternVariable.getType() );
     }
 
-    private ObjectType getPrototypeObjectType( Prototype prototype ) {
-        return objectTypeCache.computeIfAbsent( prototype.getFullName(), name -> {
-            KnowledgePackageImpl pkg = (KnowledgePackageImpl) packages.computeIfAbsent( prototype.getPackage(), this::createKiePackage );
-            FactTemplateObjectType objectType = new FactTemplateObjectType(prototypeToFactTemplate( prototype, pkg ));
-            objectType.setEvent(prototype.isEvent());
-            return objectType;
-        } );
-    }
-
     private ObjectType getClassObjectType( Class<?> patternClass ) {
         return objectTypeCache.computeIfAbsent( patternClass.getCanonicalName(), name -> {
             boolean isEvent = false;
diff --git a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/PrototypeService.java b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/PrototypeService.java
new file mode 100644
index 0000000000..66953321d9
--- /dev/null
+++ b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/PrototypeService.java
@@ -0,0 +1,50 @@
+/**
+ * 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.drools.modelcompiler;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import org.drools.base.base.ObjectType;
+import org.drools.base.common.MissingDependencyException;
+import org.drools.base.definitions.InternalKnowledgePackage;
+import org.drools.model.Variable;
+import org.kie.api.internal.utils.KieService;
+
+public interface PrototypeService extends KieService {
+    String NO_PROTOTYPE = "You're trying to use the Prototypes without having imported it. Please add the module org.drools:drools-model-prototype to your classpath.";
+
+    ObjectType getPrototypeObjectType(Map<String, ObjectType> objectTypeCache, Map<String, InternalKnowledgePackage> packages, Function<String, InternalKnowledgePackage> packageCreator, Variable patternVariable );
+
+    class Holder {
+        private static final PrototypeService INSTANCE = KieService.load(PrototypeService.class);
+    }
+
+    static PrototypeService get() {
+        return present() ? PrototypeService.Holder.INSTANCE : throwExceptionForMissingPrototype();
+    }
+
+    static boolean present() {
+        return PrototypeService.Holder.INSTANCE != null;
+    }
+
+    static <T> T throwExceptionForMissingPrototype() {
+        throw new MissingDependencyException(NO_PROTOTYPE);
+    }
+}
diff --git a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/FactFactory.java b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/FactFactory.java
deleted file mode 100644
index c774491d5a..0000000000
--- a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/FactFactory.java
+++ /dev/null
@@ -1,82 +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.drools.modelcompiler.facttemplate;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.drools.base.definitions.InternalKnowledgePackage;
-import org.drools.base.facttemplates.Event;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateImpl;
-import org.drools.base.facttemplates.FieldTemplate;
-import org.drools.base.facttemplates.FieldTemplateImpl;
-import org.drools.core.reteoo.CoreComponentFactory;
-import org.drools.model.Prototype;
-
-public class FactFactory {
-
-    private static final Map<Prototype, FactTemplate> factTemplateCache = new ConcurrentHashMap<>();
-
-    public static Fact createMapBasedFact(FactTemplate factTemplate) {
-        return new HashMapFactImpl( factTemplate );
-    }
-
-    public static Fact createMapBasedFact(FactTemplate factTemplate, Map<String, Object> valuesMap) {
-        return new HashMapFactImpl( factTemplate, valuesMap );
-    }
-
-    public static Fact createMapBasedFact(Prototype prototype) {
-        return createMapBasedFact( prototypeToFactTemplate( prototype ) );
-    }
-
-    public static Fact createMapBasedFact(Prototype prototype, Map<String, Object> valuesMap) {
-        return createMapBasedFact( prototypeToFactTemplate( prototype ), valuesMap );
-    }
-
-    public static Event createMapBasedEvent(FactTemplate factTemplate) {
-        return new HashMapEventImpl( factTemplate );
-    }
-
-    public static Event createMapBasedEvent(FactTemplate factTemplate, Map<String, Object> valuesMap) {
-        return new HashMapEventImpl( factTemplate, valuesMap );
-    }
-
-    public static Event createMapBasedEvent(Prototype prototype) {
-        return createMapBasedEvent( prototypeToFactTemplate( prototype ) );
-    }
-
-    public static Event createMapBasedEvent(Prototype prototype, Map<String, Object> valuesMap) {
-        return createMapBasedEvent( prototypeToFactTemplate( prototype ), valuesMap );
-    }
-
-    public static FactTemplate prototypeToFactTemplate( Prototype prototype ) {
-        return factTemplateCache.computeIfAbsent(prototype, p -> prototypeToFactTemplate( p, CoreComponentFactory.get().createKnowledgePackage( p.getPackage() ) ) );
-    }
-
-    public static FactTemplate prototypeToFactTemplate( Prototype prototype, InternalKnowledgePackage pkg ) {
-        FieldTemplate[] fieldTemplates = new FieldTemplate[prototype.getFieldNames().size()];
-        int i = 0;
-        for (String fieldName : prototype.getFieldNames()) {
-            fieldTemplates[i++] = new FieldTemplateImpl( fieldName, prototype.getField(fieldName).getType() );
-        }
-        return new FactTemplateImpl( pkg, prototype.getName(), fieldTemplates );
-    }
-}
diff --git a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/PrototypeFactFactoryImpl.java b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/PrototypeFactFactoryImpl.java
deleted file mode 100644
index 65b1c1bfac..0000000000
--- a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/PrototypeFactFactoryImpl.java
+++ /dev/null
@@ -1,38 +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.drools.modelcompiler.facttemplate;
-
-import java.util.Map;
-
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeFact;
-import org.drools.model.PrototypeFactFactory;
-
-public class PrototypeFactFactoryImpl implements PrototypeFactFactory {
-
-    @Override
-    public PrototypeFact createMapBasedFact(Prototype prototype) {
-        return (PrototypeFact) FactFactory.createMapBasedFact(prototype);
-    }
-
-    @Override
-    public PrototypeFact createMapBasedFact(Prototype prototype, Map<String, Object> valuesMap) {
-        return (PrototypeFact) FactFactory.createMapBasedFact(prototype, valuesMap);
-    }
-}
diff --git a/drools-model/drools-model-compiler/src/main/resources/META-INF/services/org.drools.model.PrototypeFactFactory b/drools-model/drools-model-compiler/src/main/resources/META-INF/services/org.drools.model.PrototypeFactFactory
deleted file mode 100644
index 04d13332a2..0000000000
--- a/drools-model/drools-model-compiler/src/main/resources/META-INF/services/org.drools.model.PrototypeFactFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.drools.modelcompiler.facttemplate.PrototypeFactFactoryImpl
\ No newline at end of file
diff --git a/drools-model/drools-model-prototype/pom.xml b/drools-model/drools-model-prototype/pom.xml
new file mode 100644
index 0000000000..a274b5cb63
--- /dev/null
+++ b/drools-model/drools-model-prototype/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.drools</groupId>
+    <artifactId>drools-model</artifactId>
+    <version>999-SNAPSHOT</version>
+  </parent>
+
+  <name>Drools :: Canonical Model :: Prototype</name>
+  <artifactId>drools-model-prototype</artifactId>
+
+  <properties>
+    <java.module.name>org.drools.model.prototype</java.module.name>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-base</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-canonical-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-model-compiler</artifactId>
+    </dependency>
+
+    <dependency><!-- For unit test logging: configure in src/test/resources/logback-test.xml -->
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeDSL.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java
similarity index 76%
rename from drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeDSL.java
rename to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java
index c9443cd479..1952375d11 100644
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeDSL.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java
@@ -16,60 +16,48 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.model;
-
-import org.drools.model.functions.Function1;
-import org.drools.model.functions.Predicate1;
-import org.drools.model.functions.Predicate2;
-import org.drools.model.functions.Predicate3;
-import org.drools.model.functions.temporal.TemporalPredicate;
-import org.drools.model.impl.PrototypeImpl;
-import org.drools.model.impl.PrototypeVariableImpl;
+package org.drools.model.prototype;
 
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Function;
+
+import org.drools.model.AlphaIndex;
+import org.drools.model.BetaIndex;
+import org.drools.model.ConstraintOperator;
+import org.drools.model.Index;
+import org.drools.model.PatternDSL;
+import org.drools.model.functions.Function1;
+import org.drools.model.functions.Predicate1;
+import org.drools.model.functions.Predicate2;
+import org.drools.model.functions.Predicate3;
+import org.drools.model.functions.temporal.TemporalPredicate;
+import org.drools.model.prototype.impl.PrototypeVariableImpl;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 import static java.util.UUID.randomUUID;
 import static org.drools.model.PatternDSL.alphaIndexedBy;
 import static org.drools.model.PatternDSL.betaIndexedBy;
 import static org.drools.model.PatternDSL.reactOn;
-import static org.drools.model.PrototypeExpression.prototypeArrayItem;
-import static org.drools.model.PrototypeExpression.prototypeField;
+import static org.drools.model.prototype.PrototypeExpression.prototypeArrayItem;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
 
 public class PrototypeDSL {
 
-    public static final Prototype DEFAULT_PROTOTYPE = prototype("$DEFAULT_PROTOTYPE$");
+    static final PrototypeFact DEFAULT_PROTOTYPE = prototype("$DEFAULT_PROTOTYPE$").asFact();
 
-    public static Prototype prototype(String name) {
-        return new PrototypeImpl(name);
+    public static PrototypeFact prototypeFact(String name) {
+        return prototype(name).asFact();
     }
 
-    public static Prototype prototype(String name, String... fields) {
-        return new PrototypeImpl(name, fields);
-    }
-
-    public static Prototype prototype(String name, Prototype.Field... fields) {
-        return new PrototypeImpl(name, fields);
-    }
-
-    public static Prototype.Field field(String name) {
-        return new PrototypeImpl.FieldImpl(name);
-    }
-
-    public static Prototype.Field field(String name, Function<PrototypeFact, Object> extractor) {
-        return new PrototypeImpl.FieldImpl(name, extractor);
-    }
-
-    public static Prototype.Field field(String name, Class<?> type) {
-        return new PrototypeImpl.FieldImpl(name, type);
-    }
-
-    public static Prototype.Field field(String name, Class<?> type, Function<PrototypeFact, Object> extractor) {
-        return new PrototypeImpl.FieldImpl(name, type, extractor);
+    public static PrototypeEvent prototypeEvent(String name) {
+        return prototype(name).asEvent();
     }
 
     public static PrototypeVariable variable(Prototype prototype) {
@@ -84,7 +72,7 @@ public class PrototypeDSL {
         return new PrototypePatternDefImpl(protoVar);
     }
 
-    public interface PrototypePatternDef extends PatternDSL.PatternDef<PrototypeFact> {
+    public interface PrototypePatternDef extends PatternDSL.PatternDef<PrototypeFactInstance> {
         PrototypePatternDef expr(String fieldName, ConstraintOperator operator, Object value);
         PrototypePatternDef expr(PrototypeExpression left, ConstraintOperator operator, PrototypeExpression right);
 
@@ -98,7 +86,7 @@ public class PrototypeDSL {
         PrototypePatternDef or();
     }
 
-    public static class PrototypePatternDefImpl extends PatternDSL.PatternDefImpl<PrototypeFact> implements PrototypePatternDef {
+    public static class PrototypePatternDefImpl extends PatternDSL.PatternDefImpl<PrototypeFactInstance> implements PrototypePatternDef {
         public PrototypePatternDefImpl(PrototypeVariable variable) {
             super(variable);
         }
@@ -133,7 +121,7 @@ public class PrototypeDSL {
             }
 
             Prototype prototype = getPrototype();
-            Function1<PrototypeFact, Object> leftExtractor = left.asFunction(prototype);
+            Function1<PrototypeFactInstance, Object> leftExtractor = left.asFunction(prototype);
 
             Set<String> reactOnFields = new HashSet<>();
             reactOnFields.addAll(left.getImpactedFields());
@@ -147,10 +135,9 @@ public class PrototypeDSL {
             return this;
         }
 
-        private static AlphaIndex createAlphaIndex(PrototypeExpression left, ConstraintOperator operator, PrototypeExpression right, Prototype prototype, Function1<PrototypeFact, Object> leftExtractor) {
-            if (left.getIndexingKey().isPresent() && right instanceof PrototypeExpression.FixedValue && operator instanceof Index.ConstraintType) {
+        private static AlphaIndex createAlphaIndex(PrototypeExpression left, ConstraintOperator operator, PrototypeExpression right, Prototype prototype, Function1<PrototypeFactInstance, Object> leftExtractor) {
+            if (left.getIndexingKey().isPresent() && right instanceof PrototypeExpression.FixedValue && operator instanceof Index.ConstraintType constraintType) {
                 String fieldName = left.getIndexingKey().get();
-                Index.ConstraintType constraintType = (Index.ConstraintType) operator;
                 Prototype.Field field = prototype.getField(fieldName);
                 Object value = ((PrototypeExpression.FixedValue) right).getValue();
 
@@ -195,12 +182,11 @@ public class PrototypeDSL {
         }
 
         private BetaIndex createBetaIndex(PrototypeExpression left, ConstraintOperator operator, PrototypeExpression right, Prototype prototype, Prototype otherPrototype) {
-            if (left.getIndexingKey().isPresent() && operator instanceof Index.ConstraintType && right.getIndexingKey().isPresent()) {
+            if (left.getIndexingKey().isPresent() && operator instanceof Index.ConstraintType constraintType && right.getIndexingKey().isPresent()) {
                 String fieldName = left.getIndexingKey().get();
-                Index.ConstraintType constraintType = (Index.ConstraintType) operator;
                 Prototype.Field field = prototype.getField(fieldName);
-                Function1<PrototypeFact, Object> extractor = left.asFunction(prototype);
-                Function1<PrototypeFact, Object> otherExtractor = right.asFunction(otherPrototype);
+                Function1<PrototypeFactInstance, Object> extractor = left.asFunction(prototype);
+                Function1<PrototypeFactInstance, Object> otherExtractor = right.asFunction(otherPrototype);
 
                 Class<Object> fieldClass = (Class<Object>) (field != null && field.isTyped() ? field.getType() : Object.class);
                 return betaIndexedBy( fieldClass, constraintType, getFieldIndex(prototype, fieldName, field), extractor, otherExtractor );
@@ -210,13 +196,14 @@ public class PrototypeDSL {
 
         @Override
         public PrototypePatternDef expr(TemporalPredicate temporalPredicate, PrototypeVariable other) {
+            if (!getPrototype().isEvent() || !other.getPrototype().isEvent()) {
+                throw new UnsupportedOperationException("Use of temporal predicates is allowed only on events, not on facts.");
+            }
             expr( randomUUID().toString(), other, temporalPredicate );
-            getPrototype().setAsEvent(true);
-            other.getPrototype().setAsEvent(true);
             return this;
         }
 
-        private Predicate1<PrototypeFact> asPredicate1(Function1<PrototypeFact, Object> left, ConstraintOperator operator, Function1<PrototypeFact, Object> right) {
+        private Predicate1<PrototypeFactInstance> asPredicate1(Function1<PrototypeFactInstance, Object> left, ConstraintOperator operator, Function1<PrototypeFactInstance, Object> right) {
             return p -> {
                 Object leftValue = left.apply(p);
                 Object rightValue = right.apply(p);
@@ -224,7 +211,7 @@ public class PrototypeDSL {
             };
         }
 
-        private Predicate2<PrototypeFact, PrototypeFact> asPredicate2(Function1<PrototypeFact, Object> extractor, ConstraintOperator operator, Function1<PrototypeFact, Object> otherExtractor) {
+        private Predicate2<PrototypeFactInstance, PrototypeFactInstance> asPredicate2(Function1<PrototypeFactInstance, Object> extractor, ConstraintOperator operator, Function1<PrototypeFactInstance, Object> otherExtractor) {
             return (p1, p2) -> {
                 Object leftValue = extractor.apply(p1);
                 Object rightValue = otherExtractor.apply(p2);
@@ -236,23 +223,21 @@ public class PrototypeDSL {
             PrototypeVariable leftVar = getPrototypeVariable();
             PrototypeVariable[] protoVars = findRightPrototypeVariables(right, leftVar);
 
-            switch (protoVars.length) {
-                case 2:
-                    expr( "expr:" + left + ":" + operator + ":" + right,
-                            protoVars[0], protoVars[1],
-                            asPredicate3(leftVar, left, operator, (PrototypeExpression.EvaluableExpression) right, protoVars)
-                        );
-                    break;
-                default:
-                    throw new UnsupportedOperationException();
+            if (protoVars.length == 2) {
+                expr("expr:" + left + ":" + operator + ":" + right,
+                     protoVars[0], protoVars[1],
+                     asPredicate3(leftVar, left, operator, (PrototypeExpression.EvaluableExpression) right, protoVars)
+                );
+            } else {
+                throw new UnsupportedOperationException();
             }
 
             return this;
         }
 
-        private Predicate3<PrototypeFact, PrototypeFact, PrototypeFact> asPredicate3(PrototypeVariable leftVar, PrototypeExpression left, ConstraintOperator operator, PrototypeExpression.EvaluableExpression right, PrototypeVariable[] protoVars) {
+        private Predicate3<PrototypeFactInstance, PrototypeFactInstance, PrototypeFactInstance> asPredicate3(PrototypeVariable leftVar, PrototypeExpression left, ConstraintOperator operator, PrototypeExpression.EvaluableExpression right, PrototypeVariable[] protoVars) {
             return (l, r1, r2) -> {
-                Map<PrototypeVariable, PrototypeFact> factsMap = new HashMap<>();
+                Map<PrototypeVariable, PrototypeFactInstance> factsMap = new HashMap<>();
                 factsMap.put(leftVar, l);
                 factsMap.put(protoVars[0], r1);
                 factsMap.put(protoVars[1], r2);
@@ -281,12 +266,12 @@ public class PrototypeDSL {
         }
     }
 
-    public static class PrototypeSubPatternDefImpl<T> extends PrototypePatternDefImpl {
+    public static class PrototypeSubPatternDefImpl extends PrototypePatternDefImpl {
         private final PrototypePatternDefImpl parent;
         private final PatternDSL.LogicalCombiner combiner;
 
         public PrototypeSubPatternDefImpl(PrototypePatternDefImpl parent, PatternDSL.LogicalCombiner combiner ) {
-            super((PrototypeVariable) parent.variable);
+            super((PrototypeVariable) parent.getFirstVariable());
             this.parent = parent;
             this.combiner = combiner;
         }
@@ -296,7 +281,7 @@ public class PrototypeDSL {
             if (combiner == PatternDSL.LogicalCombiner.OR) {
                 throw new UnsupportedOperationException();
             }
-            parent.items.add( new PatternDSL.CombinedPatternExprItem<>( combiner, this.getItems() ));
+            parent.getItems().add( new PatternDSL.CombinedPatternExprItem<>( combiner, this.getItems() ));
             return parent;
         }
 
@@ -305,7 +290,7 @@ public class PrototypeDSL {
             if (combiner == PatternDSL.LogicalCombiner.AND) {
                 throw new UnsupportedOperationException();
             }
-            parent.items.add( new PatternDSL.CombinedPatternExprItem<>( combiner, this.getItems() ));
+            parent.getItems().add( new PatternDSL.CombinedPatternExprItem<>( combiner, this.getItems() ));
             return parent;
         }
     }
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeExpression.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeExpression.java
similarity index 90%
rename from drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeExpression.java
rename to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeExpression.java
index 4071ed05a7..26c1169dc3 100644
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeExpression.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeExpression.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.model;
+package org.drools.model.prototype;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -29,14 +29,16 @@ import java.util.Set;
 
 import org.drools.model.functions.Function1;
 import org.drools.model.functions.Function2;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 public interface PrototypeExpression {
 
     interface EvaluableExpression {
-        Object evaluate(Map<PrototypeVariable, PrototypeFact> factsMap);
+        Object evaluate(Map<PrototypeVariable, PrototypeFactInstance> factsMap);
     }
 
-    Function1<PrototypeFact, Object> asFunction(Prototype prototype);
+    Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype);
 
     Collection<String> getImpactedFields();
     
@@ -104,7 +106,7 @@ public interface PrototypeExpression {
         }
 
         @Override
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
             return x -> value;
         }
 
@@ -123,7 +125,7 @@ public interface PrototypeExpression {
         }
 
         @Override
-        public Object evaluate(Map<PrototypeVariable, PrototypeFact> factsMap) {
+        public Object evaluate(Map<PrototypeVariable, PrototypeFactInstance> factsMap) {
             return value;
         }
     }
@@ -133,7 +135,7 @@ public interface PrototypeExpression {
         INSTANCE;
 
         @Override
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
             return p -> p;
         }
 
@@ -157,7 +159,7 @@ public interface PrototypeExpression {
         }
 
         @Override
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
             return prototype.getFieldValueExtractor(fieldName)::apply;
         }
 
@@ -200,7 +202,7 @@ public interface PrototypeExpression {
         }
 
         @Override
-        public Object evaluate(Map<PrototypeVariable, PrototypeFact> factsMap) {
+        public Object evaluate(Map<PrototypeVariable, PrototypeFactInstance> factsMap) {
             return protoVar.getPrototype().getFieldValueExtractor(getIndexingKey().get()).apply(factsMap.get(protoVar));
         }
 
@@ -221,7 +223,7 @@ public interface PrototypeExpression {
         }
 
         @Override
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
             return fact -> extractArrayItem( prototype.getFieldValueExtractor(fieldName).apply(fact) );
         }
 
@@ -263,19 +265,21 @@ public interface PrototypeExpression {
             this.first = first;
             this.second = second;
         }
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
-            return first.asFunction(prototype).andThen(this::object2PrototypeFact).andThen(second.asFunction(prototype));
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
+            return first.asFunction(prototype).andThen(this::object2PrototypeFactInstance).andThen(second.asFunction(prototype));
         }
 
-        private PrototypeFact object2PrototypeFact(Object object) {
+        private PrototypeFactInstance object2PrototypeFactInstance(Object object) {
             if (object == Prototype.UNDEFINED_VALUE) {
-                return PrototypeFactFactory.get().createMapBasedFact(PrototypeDSL.DEFAULT_PROTOTYPE);
+                return PrototypeDSL.DEFAULT_PROTOTYPE.newInstance();
             }
-            if (object instanceof PrototypeFact) {
-                return (PrototypeFact) object;
+            if (object instanceof PrototypeFactInstance) {
+                return (PrototypeFactInstance) object;
             }
             if (object instanceof Map) {
-                return PrototypeFactFactory.get().createMapBasedFact(PrototypeDSL.DEFAULT_PROTOTYPE, (Map<String, Object>) object);
+                PrototypeFactInstance fact = PrototypeDSL.DEFAULT_PROTOTYPE.newInstance();
+                ((Map<String, Object>) object).forEach(fact::put);
+                return fact;
             }
             throw new UnsupportedOperationException("Cannot convert " + object + " into a Prototype");
         }
@@ -392,8 +396,8 @@ public interface PrototypeExpression {
         private final PrototypeExpression right;
 
         @Override
-        public Function1<PrototypeFact, Object> asFunction(Prototype prototype) {
-            return (PrototypeFact fact) -> {
+        public Function1<PrototypeFactInstance, Object> asFunction(Prototype prototype) {
+            return (PrototypeFactInstance fact) -> {
                 Object leftValue = left.asFunction(prototype).apply(fact);
                 Object rightValue = right.asFunction(prototype).apply(fact);
                 return op.operator.apply(leftValue, rightValue);
@@ -426,7 +430,7 @@ public interface PrototypeExpression {
         }
 
         @Override
-        public Object evaluate(Map<PrototypeVariable, PrototypeFact> factsMap) {
+        public Object evaluate(Map<PrototypeVariable, PrototypeFactInstance> factsMap) {
             Object leftValue = ((EvaluableExpression) left).evaluate(factsMap);
             Object rightValue = ((EvaluableExpression) right).evaluate(factsMap);
             return op.operator.apply(leftValue, rightValue);
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeVariable.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeVariable.java
similarity index 78%
copy from drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeVariable.java
copy to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeVariable.java
index 9bba12c0a8..8f9fd5949b 100644
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/PrototypeVariable.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeVariable.java
@@ -16,8 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.model;
+package org.drools.model.prototype;
 
-public interface PrototypeVariable extends Variable<PrototypeFact> {
+import org.drools.model.Variable;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
+
+public interface PrototypeVariable extends Variable<PrototypeFactInstance> {
     Prototype getPrototype();
+
+    @Override
+    default boolean isPrototype() {
+        return true;
+    }
 }
diff --git a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/HashMapEventImpl.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/HashMapEventImpl.java
similarity index 71%
rename from drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/HashMapEventImpl.java
rename to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/HashMapEventImpl.java
index 0b0005f2a7..b929f0a632 100644
--- a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/HashMapEventImpl.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/HashMapEventImpl.java
@@ -16,33 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.modelcompiler.facttemplate;
+package org.drools.model.prototype.impl;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
-import org.drools.base.facttemplates.Event;
-import org.drools.base.facttemplates.FactTemplate;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeEventInstance;
 
 import static org.drools.model.functions.temporal.TimeUtil.unitToLong;
 
-public class HashMapEventImpl extends HashMapFactImpl implements Event {
+public class HashMapEventImpl extends HashMapFactImpl implements PrototypeEventInstance {
 
     private long timestamp = -1;
     private long expiration = Long.MAX_VALUE;
 
-    public HashMapEventImpl(FactTemplate factTemplate) {
-        this( factTemplate, new HashMap<>() );
+    public HashMapEventImpl(Prototype prototype) {
+        this( prototype, new HashMap<>() );
     }
 
-    public HashMapEventImpl(FactTemplate factTemplate, Map<String, Object> valuesMap) {
-        super(factTemplate, valuesMap);
+    public HashMapEventImpl(Prototype prototype, Map<String, Object> valuesMap) {
+        super(prototype, valuesMap);
     }
 
-    public HashMapEventImpl(UUID uuid, FactTemplate factTemplate, Map<String, Object> valuesMap, long timestamp, long expiration) {
-        super(uuid, factTemplate, valuesMap);
+    public HashMapEventImpl(UUID uuid, Prototype prototype, Map<String, Object> valuesMap, long timestamp, long expiration) {
+        super(uuid, prototype, valuesMap);
         this.timestamp = timestamp;
         this.expiration = expiration;
     }
@@ -65,6 +65,6 @@ public class HashMapEventImpl extends HashMapFactImpl implements Event {
 
     @Override
     public String toString() {
-        return "Event " + factTemplate.getName() + " with values = " + valuesMap;
+        return "Event " + prototype.getFullName() + " with values = " + valuesMap;
     }
 }
diff --git a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/HashMapFactImpl.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/HashMapFactImpl.java
similarity index 72%
rename from drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/HashMapFactImpl.java
rename to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/HashMapFactImpl.java
index f036180e22..ac085447cc 100644
--- a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/facttemplate/HashMapFactImpl.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/HashMapFactImpl.java
@@ -16,38 +16,37 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.modelcompiler.facttemplate;
+package org.drools.model.prototype.impl;
 
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.model.PrototypeFact;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
 
-public class HashMapFactImpl implements Fact, PrototypeFact, Serializable {
+public class HashMapFactImpl implements PrototypeFactInstance, Serializable {
 
     protected final UUID uuid;
 
-    protected final FactTemplate factTemplate;
+    protected final Prototype prototype;
 
     protected final Map<String, Object> valuesMap;
 
-    public HashMapFactImpl( FactTemplate factTemplate ) {
-        this( factTemplate, new HashMap<>() );
+    public HashMapFactImpl( Prototype prototype ) {
+        this( prototype, new HashMap<>() );
     }
 
-    public HashMapFactImpl( FactTemplate factTemplate, Map<String, Object> valuesMap ) {
+    public HashMapFactImpl( Prototype prototype, Map<String, Object> valuesMap ) {
         this.uuid = UUID.randomUUID();
-        this.factTemplate = factTemplate;
+        this.prototype = prototype;
         this.valuesMap = valuesMap;
     }
 
-    public HashMapFactImpl( UUID uuid, FactTemplate factTemplate, Map<String, Object> valuesMap ) {
+    public HashMapFactImpl( UUID uuid, Prototype prototype, Map<String, Object> valuesMap ) {
         this.uuid = uuid;
-        this.factTemplate = factTemplate;
+        this.prototype = prototype;
         this.valuesMap = valuesMap;
     }
 
@@ -56,8 +55,8 @@ public class HashMapFactImpl implements Fact, PrototypeFact, Serializable {
     }
 
     @Override
-    public FactTemplate getFactTemplate() {
-        return factTemplate;
+    public Prototype getPrototype() {
+        return prototype;
     }
 
     @Override
@@ -71,7 +70,7 @@ public class HashMapFactImpl implements Fact, PrototypeFact, Serializable {
     }
 
     @Override
-    public void set( String name, Object value ) {
+    public void put(String name, Object value ) {
         valuesMap.put(name, value);
     }
 
@@ -82,7 +81,7 @@ public class HashMapFactImpl implements Fact, PrototypeFact, Serializable {
 
     @Override
     public String toString() {
-        return "Fact " + factTemplate.getName() + " with values = " + valuesMap;
+        return "Fact " + prototype.getFullName() + " with values = " + valuesMap;
     }
 
     @Override
diff --git a/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeBuilderImpl.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeBuilderImpl.java
new file mode 100644
index 0000000000..bf5fad5e73
--- /dev/null
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeBuilderImpl.java
@@ -0,0 +1,82 @@
+/**
+ * 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.drools.model.prototype.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeBuilder;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
+
+public class PrototypeBuilderImpl implements PrototypeBuilder {
+
+    private final String name;
+
+    private final List<Prototype.Field> fields = new ArrayList<>();
+
+    public PrototypeBuilderImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public PrototypeBuilder withField(String name) {
+        fields.add(new PrototypeImpl.FieldImpl(name));
+        return this;
+    }
+
+    @Override
+    public PrototypeBuilder withField(String name, Function<PrototypeFactInstance, Object> extractor) {
+        fields.add(new PrototypeImpl.FieldImpl(name, extractor));
+        return this;
+    }
+
+    @Override
+    public PrototypeBuilder withField(String name, Class<?> type) {
+        fields.add(new PrototypeImpl.FieldImpl(name, type));
+        return this;
+    }
+
+    @Override
+    public PrototypeBuilder withField(String name, Class<?> type, Function<PrototypeFactInstance, Object> extractor) {
+        fields.add(new PrototypeImpl.FieldImpl(name, type, extractor));
+        return this;
+    }
+
+    @Override
+    public PrototypeFact asFact() {
+        return new PrototypeFactImpl( name, fields );
+    }
+
+    @Override
+    public PrototypeEvent asEvent() {
+        return new PrototypeEventImpl( name, fields );
+    }
+
+    public static class CreatorImpl implements PrototypeBuilder.Creator {
+
+        @Override
+        public PrototypeBuilder newPrototype(String name) {
+            return new PrototypeBuilderImpl(name);
+        }
+    }
+}
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/Event.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeEventImpl.java
similarity index 62%
copy from drools-base/src/main/java/org/drools/base/facttemplates/Event.java
copy to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeEventImpl.java
index 8692847bdd..e591323c17 100644
--- a/drools-base/src/main/java/org/drools/base/facttemplates/Event.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeEventImpl.java
@@ -16,19 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.base.facttemplates;
+package org.drools.model.prototype.impl;
 
-import java.util.concurrent.TimeUnit;
+import java.util.List;
 
-public interface Event extends Fact {
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeEventInstance;
 
-    long getTimestamp();
+public class PrototypeEventImpl extends PrototypeImpl implements PrototypeEvent {
 
-    long getExpiration();
+    public PrototypeEventImpl(String name, List<Field> fields ) {
+        super(name, fields);
+    }
 
-    Event withExpiration( long value, TimeUnit unit );
+    @Override
+    public PrototypeEventInstance newInstance() {
+        return new HashMapEventImpl(this);
+    }
 
-    default boolean isEvent() {
+    @Override
+    public boolean isEvent() {
         return true;
     }
 }
diff --git a/drools-base/src/main/java/org/drools/base/facttemplates/Fact.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeFactImpl.java
similarity index 62%
copy from drools-base/src/main/java/org/drools/base/facttemplates/Fact.java
copy to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeFactImpl.java
index 3073a652b5..44cc9c869f 100644
--- a/drools-base/src/main/java/org/drools/base/facttemplates/Fact.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeFactImpl.java
@@ -16,21 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.base.facttemplates;
+package org.drools.model.prototype.impl;
 
-import java.util.Map;
+import java.util.List;
 
-public interface Fact {
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
 
-    Object get(String name);
+public class PrototypeFactImpl extends PrototypeImpl implements PrototypeFact {
 
-    void set(String name, Object value);
-
-    Map<String, Object> asMap();
+    public PrototypeFactImpl( String name, List<Field> fields ) {
+        super(name, fields);
+    }
 
-    FactTemplate getFactTemplate();
+    @Override
+    public PrototypeFactInstance newInstance() {
+        return new HashMapFactImpl(this);
+    }
 
-    default boolean isEvent() {
+    @Override
+    public boolean isEvent() {
         return false;
     }
 }
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/PrototypeImpl.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeImpl.java
similarity index 63%
rename from drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/PrototypeImpl.java
rename to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeImpl.java
index 002e2c3acf..989dafe042 100644
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/PrototypeImpl.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeImpl.java
@@ -16,49 +16,59 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.model.impl;
+package org.drools.model.prototype.impl;
 
+import java.io.Serializable;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.function.Function;
-import java.util.stream.Stream;
 
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeFact;
+import org.drools.core.reteoo.CoreComponentFactory;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 import static org.drools.model.impl.RuleBuilder.DEFAULT_PACKAGE;
 
-public class PrototypeImpl implements Prototype {
+public abstract class PrototypeImpl implements Prototype, Serializable {
 
     private final String pkg;
     private final String name;
     private final SortedMap<String, Field> fields;
 
-    private boolean event;
+    public PrototypeImpl( String fulllName, List<Field> fields ) {
+        int lastDot = fulllName.lastIndexOf('.');
+        this.pkg = lastDot > 0 ? fulllName.substring(0, lastDot) : DEFAULT_PACKAGE;
+        this.name = lastDot > 0 ? fulllName.substring(lastDot+1) : fulllName;
+        this.fields = initFields(fields);
+        registerPrototype();
+    }
 
-    public PrototypeImpl( String name ) {
-        this(name, new Field[0]);
+    public PrototypeImpl( String pkg, String name, List<Field> fields ) {
+        this.pkg = pkg != null && !pkg.isEmpty() ? pkg : DEFAULT_PACKAGE;
+        this.name = name;
+        this.fields = initFields(fields);
+        registerPrototype();
     }
 
-    public PrototypeImpl( String name, String... fields ) {
-        this(name, Stream.of(fields).map(FieldImpl::new).toArray(Field[]::new));
+    private void registerPrototype() {
+        CoreComponentFactory.get().createKnowledgePackage(pkg).addPrototype(this);
     }
 
-    public PrototypeImpl( String name, Field... fields ) {
-        int lastDot = name.lastIndexOf('.');
-        this.pkg = lastDot > 0 ? name.substring(0, lastDot) : DEFAULT_PACKAGE;
-        this.name = lastDot > 0 ? name.substring(lastDot+1) : name;
-        if (fields != null && fields.length > 0) {
-            this.fields = new TreeMap<>();
+    private SortedMap<String, Field> initFields(List<Field> fields) {
+        final SortedMap<String, Field> sortedFields;
+        if (fields != null && !fields.isEmpty()) {
+            sortedFields = new TreeMap<>();
             for (Field field : fields) {
-                this.fields.put(field.getName(), field);
+                sortedFields.put(field.getName(), field);
             }
         } else {
-            this.fields = Collections.emptySortedMap();
+            sortedFields = Collections.emptySortedMap();
         }
+        return sortedFields;
     }
 
     @Override
@@ -77,7 +87,7 @@ public class PrototypeImpl implements Prototype {
     }
 
     @Override
-    public Field getField(String name) {
+    public Prototype.Field getField(String name) {
         return fields.get(name);
     }
 
@@ -96,7 +106,7 @@ public class PrototypeImpl implements Prototype {
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+        if (!(o instanceof PrototypeImpl)) return false;
         PrototypeImpl prototype = (PrototypeImpl) o;
         return pkg.equals(prototype.pkg) && name.equals(prototype.name) && fields.equals(prototype.fields);
     }
@@ -106,18 +116,9 @@ public class PrototypeImpl implements Prototype {
         return Objects.hash(pkg, name, fields);
     }
 
-    public boolean isEvent() {
-        return event;
-    }
-
-    public PrototypeImpl setAsEvent(boolean event) {
-        this.event = event;
-        return this;
-    }
-
-    public static class FieldImpl implements Prototype.Field {
+    public static class FieldImpl implements Prototype.Field, Serializable {
         private final String name;
-        private final Function<PrototypeFact, Object> extractor;
+        private final Function<PrototypeFactInstance, Object> extractor;
         private final boolean typed;
         private final Class<?> type;
 
@@ -125,7 +126,7 @@ public class PrototypeImpl implements Prototype {
             this(name, p -> p.get(name));
         }
 
-        public FieldImpl( String name, Function<PrototypeFact, Object> extractor ) {
+        public FieldImpl( String name, Function<PrototypeFactInstance, Object> extractor ) {
             this.name = name;
             this.extractor = extractor;
             this.type = Object.class;
@@ -136,7 +137,7 @@ public class PrototypeImpl implements Prototype {
             this(name, type, p -> p.get(name));
         }
 
-        public FieldImpl( String name, Class<?> type, Function<PrototypeFact, Object> extractor ) {
+        public FieldImpl( String name, Class<?> type, Function<PrototypeFactInstance, Object> extractor ) {
             this.name = name;
             this.extractor = extractor;
             this.type = type;
@@ -149,7 +150,7 @@ public class PrototypeImpl implements Prototype {
         }
 
         @Override
-        public Function<PrototypeFact, Object> getExtractor() {
+        public Function<PrototypeFactInstance, Object> getExtractor() {
             return extractor;
         }
 
diff --git a/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeServiceImpl.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeServiceImpl.java
new file mode 100644
index 0000000000..204084f7d6
--- /dev/null
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeServiceImpl.java
@@ -0,0 +1,44 @@
+/**
+ * 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.drools.model.prototype.impl;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import org.drools.base.base.ObjectType;
+import org.drools.base.definitions.InternalKnowledgePackage;
+import org.drools.base.definitions.impl.KnowledgePackageImpl;
+import org.drools.base.prototype.PrototypeObjectType;
+import org.drools.model.Variable;
+import org.drools.model.prototype.PrototypeVariable;
+import org.drools.modelcompiler.PrototypeService;
+import org.kie.api.prototype.Prototype;
+
+public class PrototypeServiceImpl implements PrototypeService {
+
+    public ObjectType getPrototypeObjectType(Map<String, ObjectType> objectTypeCache, Map<String, InternalKnowledgePackage> packages, Function<String, InternalKnowledgePackage> packageCreator, Variable patternVariable ) {
+        Prototype prototype = ((PrototypeVariable) patternVariable).getPrototype();
+        return objectTypeCache.computeIfAbsent( prototype.getFullName(), name -> {
+            KnowledgePackageImpl pkg = (KnowledgePackageImpl) packages.computeIfAbsent(prototype.getPackage(), packageCreator );
+            PrototypeObjectType objectType = new PrototypeObjectType(prototype);
+            objectType.setEvent(prototype.isEvent());
+            return objectType;
+        } );
+    }
+}
diff --git a/drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/PrototypeVariableImpl.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeVariableImpl.java
similarity index 76%
rename from drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/PrototypeVariableImpl.java
rename to drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeVariableImpl.java
index f1ca5d4a18..08c9c99120 100644
--- a/drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/PrototypeVariableImpl.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/impl/PrototypeVariableImpl.java
@@ -16,23 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.drools.model.impl;
+package org.drools.model.prototype.impl;
 
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeFact;
-import org.drools.model.PrototypeVariable;
+import org.drools.model.impl.DeclarationImpl;
+import org.drools.model.prototype.PrototypeVariable;
+import org.kie.api.prototype.Prototype;
+import org.kie.api.prototype.PrototypeFactInstance;
 
-public class PrototypeVariableImpl extends DeclarationImpl<PrototypeFact> implements PrototypeVariable {
+public class PrototypeVariableImpl extends DeclarationImpl<PrototypeFactInstance> implements PrototypeVariable {
 
     private final Prototype prototype;
 
     public PrototypeVariableImpl( Prototype prototype ) {
-        super( PrototypeFact.class );
+        super( PrototypeFactInstance.class );
         this.prototype = prototype;
     }
 
     public PrototypeVariableImpl( Prototype prototype, String name ) {
-        super( PrototypeFact.class, name );
+        super( PrototypeFactInstance.class, name );
         this.prototype = prototype;
     }
 
diff --git a/drools-model/drools-model-prototype/src/main/resources/META-INF/services/org.drools.modelcompiler.PrototypeService b/drools-model/drools-model-prototype/src/main/resources/META-INF/services/org.drools.modelcompiler.PrototypeService
new file mode 100644
index 0000000000..b3f7c20eee
--- /dev/null
+++ b/drools-model/drools-model-prototype/src/main/resources/META-INF/services/org.drools.modelcompiler.PrototypeService
@@ -0,0 +1 @@
+org.drools.model.prototype.impl.PrototypeServiceImpl
\ No newline at end of file
diff --git a/drools-model/drools-model-prototype/src/main/resources/META-INF/services/org.kie.api.prototype.PrototypeBuilder$Creator b/drools-model/drools-model-prototype/src/main/resources/META-INF/services/org.kie.api.prototype.PrototypeBuilder$Creator
new file mode 100644
index 0000000000..2910ba470f
--- /dev/null
+++ b/drools-model/drools-model-prototype/src/main/resources/META-INF/services/org.kie.api.prototype.PrototypeBuilder$Creator
@@ -0,0 +1 @@
+org.drools.model.prototype.impl.PrototypeBuilderImpl$CreatorImpl
\ No newline at end of file
diff --git a/drools-model/drools-model-prototype/src/test/java/org/drools/model/prototype/PrototypeFieldExtractorTest.java b/drools-model/drools-model-prototype/src/test/java/org/drools/model/prototype/PrototypeFieldExtractorTest.java
new file mode 100644
index 0000000000..0b081f3c43
--- /dev/null
+++ b/drools-model/drools-model-prototype/src/test/java/org/drools/model/prototype/PrototypeFieldExtractorTest.java
@@ -0,0 +1,86 @@
+/**
+ * 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.drools.model.prototype;
+
+import org.drools.base.prototype.PrototypeFieldExtractor;
+import org.drools.base.prototype.PrototypeObjectType;
+import org.drools.base.rule.Declaration;
+import org.drools.base.rule.Pattern;
+import org.drools.base.rule.accessor.ReadAccessor;
+import org.junit.Test;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
+
+public class PrototypeFieldExtractorTest {
+    @Test
+    public void testExtractor() {
+        PrototypeFact cheesePrototype = prototype("org.sore.Cheese").withField("name", String.class).withField("price", Integer.class).asFact();
+
+        final ReadAccessor extractName = new PrototypeFieldExtractor(cheesePrototype, "name" );
+        final ReadAccessor extractPrice = new PrototypeFieldExtractor(cheesePrototype, "price" );
+
+        PrototypeFactInstance stilton = cheesePrototype.newInstance();
+        stilton.put("name", "stilton" );
+        stilton.put("price", 200 );
+
+        assertThat(extractName.getValue(null, stilton)).isEqualTo("stilton");
+
+        assertThat(extractPrice.getValue(null, stilton)).isEqualTo(200);
+
+        assertThat(extractName.isNullValue(null, stilton)).isFalse();
+        
+        stilton.put("name", null );
+
+        assertThat(extractName.isNullValue(null, stilton)).isTrue();
+        assertThat(extractPrice.isNullValue(null, stilton)).isFalse();
+
+        PrototypeFactInstance brie = cheesePrototype.newInstance();
+        brie.put("name", "brie" );
+        brie.put("price", 55 );
+
+        assertThat(extractName.getValue(null, brie)).isEqualTo("brie");
+
+        assertThat(extractPrice.getValue(null, brie)).isEqualTo(55);
+
+        assertThat(extractName.isNullValue(null, brie)).isFalse();
+        
+        brie.put("name", null );
+
+        assertThat(extractName.isNullValue(null, brie)).isTrue();
+        assertThat(extractPrice.isNullValue(null, stilton)).isFalse();
+    }
+
+    @Test
+    public void testDeclaration() {
+        PrototypeFact cheesePrototype = prototype("org.sore.Cheese").withField("name", String.class).withField("price", Integer.class).asFact();
+        ReadAccessor extractName = new PrototypeFieldExtractor(cheesePrototype, "name" );
+        Pattern pattern = new Pattern( 0, new PrototypeObjectType(cheesePrototype) );
+        Declaration declaration = new Declaration( "typeOfCheese", extractName, pattern );
+
+        PrototypeFactInstance brie = cheesePrototype.newInstance();
+        brie.put("name", "brie" );
+        brie.put("price", 55 );
+
+        // Check we can extract Declarations correctly 
+        assertThat(declaration.getValue(null, brie)).isEqualTo("brie");
+    }
+}
diff --git a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/LHSPhase.java b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/LHSPhase.java
index 7b31676cce..dd634bfcf1 100644
--- a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/LHSPhase.java
+++ b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/LHSPhase.java
@@ -35,6 +35,7 @@ import com.github.javaparser.ast.expr.EnclosedExpr;
 import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.FieldAccessExpr;
 import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
 import com.github.javaparser.ast.expr.VariableDeclarationExpr;
 import com.github.javaparser.ast.stmt.ExpressionStmt;
 import com.github.javaparser.ast.type.ClassOrInterfaceType;
@@ -54,6 +55,7 @@ import org.drools.mvelcompiler.ast.UnalteredTypedExpression;
 import org.drools.mvelcompiler.ast.VariableDeclaratorTExpr;
 import org.drools.mvelcompiler.context.Declaration;
 import org.drools.mvelcompiler.context.MvelCompilerContext;
+import org.drools.mvelcompiler.util.TypeUtils;
 import org.drools.util.ClassUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -132,7 +134,9 @@ public class LHSPhase implements DrlGenericVisitor<TypedExpression, Void> {
             // a part of a larger FieldAccessExpr. e.g. [$p.address] of [$p.address.city]
             return tryParseItAsGetter(n, fieldAccessScope)
                     .orElse(new UnalteredTypedExpression(n));
-        } else if(parentIsArrayAccessExpr(n)) {
+        } else if (fieldAccessScope.getType().map(TypeUtils::isMapAccessField).orElse(false) && parentIsAssignExpr(n)) {
+            return new MapPutExprT(fieldAccessScope, new StringLiteralExpr(n.getName().toString()), rhsOrNull(), fieldAccessScope.getType());
+        } else if (parentIsArrayAccessExpr(n)) {
             return tryParseItAsMap(n, fieldAccessScope)
                     .map(Optional::of)
                     .orElseGet(() -> tryParseItAsSetter(n, fieldAccessScope, getRHSType()))
@@ -378,6 +382,10 @@ public class LHSPhase implements DrlGenericVisitor<TypedExpression, Void> {
         return n.getParentNode().filter(p -> p instanceof ArrayAccessExpr).isPresent();
     }
 
+    private boolean parentIsAssignExpr(Node n) {
+        return n.getParentNode().filter(p -> p instanceof AssignExpr).isPresent();
+    }
+
     private Class<?> getRHSType() {
         return rhs
                 .flatMap(TypedExpression::getType)
diff --git a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/PreprocessCompiler.java b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/PreprocessCompiler.java
index 3db5bb46f5..35976cbb72 100644
--- a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/PreprocessCompiler.java
+++ b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/PreprocessCompiler.java
@@ -24,13 +24,19 @@ import java.util.Set;
 
 import com.github.javaparser.ast.Node;
 import com.github.javaparser.ast.body.VariableDeclarator;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.FieldAccessExpr;
 import com.github.javaparser.ast.expr.MethodCallExpr;
 import com.github.javaparser.ast.expr.NameExpr;
 import com.github.javaparser.ast.expr.StringLiteralExpr;
 import com.github.javaparser.ast.expr.TextBlockLiteralExpr;
 import com.github.javaparser.ast.stmt.BlockStmt;
 import org.drools.mvel.parser.MvelParser;
+import org.drools.mvel.parser.ast.expr.DrlNameExpr;
 import org.drools.mvel.parser.ast.expr.ModifyStatement;
+import org.drools.mvelcompiler.ast.MapGetExprT;
+import org.drools.mvelcompiler.ast.MapPutExprT;
 
 import static com.github.javaparser.ast.NodeList.nodeList;
 
@@ -41,7 +47,7 @@ public class PreprocessCompiler {
 
     private static final PreprocessPhase preprocessPhase = new PreprocessPhase();
 
-    public CompiledBlockResult compile(String mvelBlock) {
+    public CompiledBlockResult compile(String mvelBlock, Set<String> prototypes) {
 
         BlockStmt mvelExpression = MvelParser.parseBlock(mvelBlock);
 
@@ -53,9 +59,9 @@ public class PreprocessCompiler {
             StringLiteralExpr stringLiteralExpr = preprocessPhase.replaceTextBlockWithConcatenatedStrings(e);
 
             parentNode.ifPresent(p -> {
-                if(p instanceof VariableDeclarator) {
+                if (p instanceof VariableDeclarator) {
                     ((VariableDeclarator) p).setInitializer(stringLiteralExpr);
-                } else if(p instanceof MethodCallExpr) {
+                } else if (p instanceof MethodCallExpr) {
                     // """exampleString""".formatted("arg0", 2);
                     ((MethodCallExpr) p).setScope(stringLiteralExpr);
                 }
@@ -77,6 +83,38 @@ public class PreprocessCompiler {
                     s.remove();
                 });
 
+        if (!prototypes.isEmpty()) {
+            rewriteConsequenceForPrototype(mvelExpression, prototypes);
+        }
+
         return new CompiledBlockResult(mvelExpression.getStatements()).setUsedBindings(usedBindings);
     }
+
+    private void rewriteConsequenceForPrototype(BlockStmt ruleConsequence, Set<String> prototypes) {
+        for (AssignExpr assignExpr : ruleConsequence.findAll(AssignExpr.class)) {
+            if (assignExpr.getTarget().isFieldAccessExpr()) {
+                FieldAccessExpr fieldAccessExpr = assignExpr.getTarget().asFieldAccessExpr();
+                String assignedVariable = getAssignedVariable(fieldAccessExpr);
+                if (prototypes.contains(assignedVariable)) {
+                    assignExpr.replace(new MapPutExprT(new NameExpr(assignedVariable), new StringLiteralExpr(fieldAccessExpr.getNameAsString()),
+                                                       assignExpr.getValue(), Optional.empty()).toJavaExpression());
+                }
+            }
+        }
+
+        for (FieldAccessExpr fieldAccessExpr : ruleConsequence.findAll(FieldAccessExpr.class)) {
+            String assignedVariable = getAssignedVariable(fieldAccessExpr);
+            if (prototypes.contains(assignedVariable)) {
+                fieldAccessExpr.replace( new MapGetExprT(new NameExpr(assignedVariable), fieldAccessExpr.getNameAsString() ).toJavaExpression() );
+            }
+        }
+    }
+
+    private static String getAssignedVariable(FieldAccessExpr fieldAccessExpr) {
+        Expression scope = fieldAccessExpr.getScope();
+        if (scope instanceof DrlNameExpr drlName) {
+            return drlName.getName().toString();
+        }
+        return scope instanceof NameExpr ? scope.toString() : null;
+    }
 }
diff --git a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
index 533fab5680..6751147ef9 100644
--- a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
+++ b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/RHSPhase.java
@@ -22,7 +22,6 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -57,7 +56,6 @@ import org.drools.mvel.parser.ast.expr.BigDecimalLiteralExpr;
 import org.drools.mvel.parser.ast.expr.BigIntegerLiteralExpr;
 import org.drools.mvel.parser.ast.expr.DrlNameExpr;
 import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpression;
-import org.drools.mvel.parser.ast.expr.ListCreationLiteralExpressionElement;
 import org.drools.mvel.parser.ast.expr.MapCreationLiteralExpression;
 import org.drools.mvel.parser.ast.visitor.DrlGenericVisitor;
 import org.drools.mvelcompiler.ast.BigDecimalArithmeticExprT;
@@ -76,6 +74,7 @@ import org.drools.mvelcompiler.ast.ListAccessExprT;
 import org.drools.mvelcompiler.ast.ListExprT;
 import org.drools.mvelcompiler.ast.LongLiteralExpressionT;
 import org.drools.mvelcompiler.ast.MapExprT;
+import org.drools.mvelcompiler.ast.MapGetExprT;
 import org.drools.mvelcompiler.ast.ObjectCreationExpressionT;
 import org.drools.mvelcompiler.ast.SimpleNameTExpr;
 import org.drools.mvelcompiler.ast.StringLiteralExpressionT;
@@ -84,6 +83,7 @@ import org.drools.mvelcompiler.ast.UnalteredTypedExpression;
 import org.drools.mvelcompiler.context.Declaration;
 import org.drools.mvelcompiler.context.MvelCompilerContext;
 import org.drools.mvelcompiler.util.MethodResolutionUtils;
+import org.drools.mvelcompiler.util.TypeUtils;
 import org.drools.mvelcompiler.util.VisitorContext;
 import org.drools.util.ClassUtils;
 import org.drools.util.MethodUtils.NullType;
@@ -236,6 +236,17 @@ public class RHSPhase implements DrlGenericVisitor<TypedExpression, VisitorConte
     @Override
     public TypedExpression visit(FieldAccessExpr n, VisitorContext arg) {
         TypedExpression scope = n.getScope().accept(this, arg);
+        if (scope.getType().map(TypeUtils::isMapAccessField).orElse(false)) {
+            String key = n.getName().toString();
+
+            // "size" is an edge case and could mean both the size of the map and the value of the key "size".
+            // To keep backward compatibility it is necessary to assume that it is the size of the map,
+            // but this implies that at the moment it is not possible to read the value of the "size" key
+            // using the field access notation
+            if (!"size".equals(key)) {
+                return new MapGetExprT(scope, key);
+            }
+        }
         return n.getName().accept(this, new VisitorContext(scope));
     }
 
diff --git a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapGetExprT.java
similarity index 59%
copy from drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java
copy to drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapGetExprT.java
index f4c9b21c47..e5e809269f 100644
--- a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java
+++ b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapGetExprT.java
@@ -25,22 +25,20 @@ import com.github.javaparser.ast.Node;
 import com.github.javaparser.ast.NodeList;
 import com.github.javaparser.ast.expr.Expression;
 import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
 
-import static org.drools.mvelcompiler.util.CoercionUtils.PUT_CALL;
-import static org.drools.mvelcompiler.util.CoercionUtils.coerceMapValueToString;
+public class MapGetExprT implements TypedExpression {
 
-public class MapPutExprT implements TypedExpression {
+    private final Expression name;
+    private final String key;
 
-    private final TypedExpression name;
-    private final Expression key;
-    private final TypedExpression value;
-    private final Optional<Type> type;
+    public MapGetExprT(TypedExpression name, String key) {
+        this((Expression) name.toJavaExpression(), key);
+    }
 
-    public MapPutExprT(TypedExpression name, Expression key, TypedExpression value, Optional<Type> type) {
+    public MapGetExprT(Expression name, String key) {
         this.name = name;
         this.key = key;
-        this.value = value;
-        this.type = type;
     }
 
     @Override
@@ -50,11 +48,6 @@ public class MapPutExprT implements TypedExpression {
 
     @Override
     public Node toJavaExpression() {
-        final Expression originalValue = (Expression) this.value.toJavaExpression();
-        final Expression coercedValue = coerceMapValueToString(type, originalValue);
-
-        return new MethodCallExpr((Expression) name.toJavaExpression(),
-                                  PUT_CALL,
-                                  NodeList.nodeList(key, coercedValue));
+        return new MethodCallExpr(name, "get", NodeList.nodeList(new StringLiteralExpr(key)));
     }
 }
diff --git a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java
index f4c9b21c47..59b769f4e4 100644
--- a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java
+++ b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/ast/MapPutExprT.java
@@ -31,12 +31,16 @@ import static org.drools.mvelcompiler.util.CoercionUtils.coerceMapValueToString;
 
 public class MapPutExprT implements TypedExpression {
 
-    private final TypedExpression name;
+    private final Expression name;
     private final Expression key;
-    private final TypedExpression value;
+    private final Expression value;
     private final Optional<Type> type;
 
     public MapPutExprT(TypedExpression name, Expression key, TypedExpression value, Optional<Type> type) {
+        this((Expression) name.toJavaExpression(), key, (Expression) value.toJavaExpression(), type);
+    }
+
+    public MapPutExprT(Expression name, Expression key, Expression value, Optional<Type> type) {
         this.name = name;
         this.key = key;
         this.value = value;
@@ -50,11 +54,7 @@ public class MapPutExprT implements TypedExpression {
 
     @Override
     public Node toJavaExpression() {
-        final Expression originalValue = (Expression) this.value.toJavaExpression();
-        final Expression coercedValue = coerceMapValueToString(type, originalValue);
-
-        return new MethodCallExpr((Expression) name.toJavaExpression(),
-                                  PUT_CALL,
-                                  NodeList.nodeList(key, coercedValue));
+        final Expression coercedValue = coerceMapValueToString(type, value);
+        return new MethodCallExpr(name, PUT_CALL, NodeList.nodeList(key, coercedValue));
     }
 }
diff --git a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/TypeUtils.java b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/TypeUtils.java
index 4bdc85b263..90bd19f094 100644
--- a/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/TypeUtils.java
+++ b/drools-model/drools-mvel-compiler/src/main/java/org/drools/mvelcompiler/util/TypeUtils.java
@@ -18,10 +18,15 @@
  */
 package org.drools.mvelcompiler.util;
 
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.Map;
 
 import com.github.javaparser.StaticJavaParser;
+import org.kie.api.prototype.PrototypeFactInstance;
+
 import static org.drools.util.ClassUtils.classFromType;
+import static org.drools.util.ClassUtils.rawType;
 
 public class TypeUtils {
 
@@ -36,4 +41,18 @@ public class TypeUtils {
     public static com.github.javaparser.ast.type.Type toJPType(Class<?> c) {
         return StaticJavaParser.parseType(c.getCanonicalName());
     }
+
+    public static boolean isMapAccessField(Type type) {
+        if (type instanceof Class c) {
+            return Map.class.isAssignableFrom(c);
+        }
+        if (type instanceof ParameterizedType p) {
+            if (!Map.class.isAssignableFrom(rawType(p.getRawType()))) {
+                return false;
+            }
+            Class<?> valueType = rawType(p.getActualTypeArguments()[1]);
+            return valueType == Object.class || Map.class.isAssignableFrom(valueType) || PrototypeFactInstance.class.isAssignableFrom(valueType);
+        }
+        return false;
+    }
 }
diff --git a/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/MvelCompilerTest.java b/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/MvelCompilerTest.java
index 7de5965da1..9604a49724 100644
--- a/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/MvelCompilerTest.java
+++ b/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/MvelCompilerTest.java
@@ -1162,4 +1162,25 @@ public class MvelCompilerTest implements CompilerTest {
         test(" { java.lang.String s = \"\"\"\n string content\n \"\"\"; }",
              " { java.lang.String s = \"\"\"\n string content\n \"\"\"; }");
     }
+
+    @Test
+    public void testReadMapField() {
+        test(ctx -> ctx.addDeclaration("$p", Map.class),
+             " { String name = $p.name; }",
+             " { java.lang.String name = (java.lang.String) ($p.get(\"name\")); }");
+    }
+
+    @Test
+    public void testWriteMapField() {
+        test(ctx -> ctx.addDeclaration("$p", Map.class),
+             " { $p.name = \"Mario\"; }",
+             " { $p.put(\"name\", \"Mario\"); }");
+    }
+
+    @Test
+    public void testReadAndWriteMapField() {
+        test(ctx -> ctx.addDeclaration("$a", Map.class).addDeclaration("$b", Map.class),
+             " { $a.name = $b.name; }",
+             " { $a.put(\"name\", $b.get(\"name\")); }");
+    }
 }
\ No newline at end of file
diff --git a/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/PreprocessCompilerTest.java b/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/PreprocessCompilerTest.java
index 7d6af4e4d9..c02fc88b30 100644
--- a/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/PreprocessCompilerTest.java
+++ b/drools-model/drools-mvel-compiler/src/test/java/org/drools/mvelcompiler/PreprocessCompilerTest.java
@@ -18,6 +18,7 @@
  */
 package org.drools.mvelcompiler;
 
+import java.util.Collections;
 import java.util.function.Consumer;
 
 import org.drools.Person;
@@ -114,7 +115,7 @@ public class PreprocessCompilerTest implements CompilerTest {
                       String inputExpression,
                       String expectedResult,
                       Consumer<CompiledBlockResult> resultAssert) {
-        CompiledBlockResult compiled = new PreprocessCompiler().compile(inputExpression);
+        CompiledBlockResult compiled = new PreprocessCompiler().compile(inputExpression, Collections.emptySet());
         assertThat(compiled.resultAsString()).isEqualToIgnoringWhitespace(expectedResult);
         resultAssert.accept(compiled);
     }
diff --git a/drools-model/pom.xml b/drools-model/pom.xml
index 95c0633c99..0051e5f802 100644
--- a/drools-model/pom.xml
+++ b/drools-model/pom.xml
@@ -39,9 +39,10 @@
     <module>drools-codegen-common</module>
     <module>drools-canonical-model</module>
     <module>drools-model-compiler</module>
-    <module>drools-model-codegen</module>
     <module>drools-mvel-parser</module>
     <module>drools-mvel-compiler</module>
+    <module>drools-model-prototype</module>
+    <module>drools-model-codegen</module>
   </modules>
 
 
diff --git a/drools-mvel/src/main/java/org/drools/mvel/MVELKnowledgePackageImpl.java b/drools-mvel/src/main/java/org/drools/mvel/MVELKnowledgePackageImpl.java
index 3cbe03b069..0ee0a113cf 100644
--- a/drools-mvel/src/main/java/org/drools/mvel/MVELKnowledgePackageImpl.java
+++ b/drools-mvel/src/main/java/org/drools/mvel/MVELKnowledgePackageImpl.java
@@ -164,7 +164,7 @@ public class MVELKnowledgePackageImpl extends KnowledgePackageImpl {
             out.writeObject(this.staticImports);
             out.writeObject(this.functions);
             out.writeObject(this.accumulateFunctions);
-            out.writeObject(this.factTemplates);
+            out.writeObject(this.prototypes);
             out.writeObject(this.globals);
             out.writeBoolean(this.valid);
             out.writeBoolean(this.needStreamMode);
@@ -212,7 +212,7 @@ public class MVELKnowledgePackageImpl extends KnowledgePackageImpl {
         this.staticImports = (Set) in.readObject();
         this.functions = (Map<String, Function>) in.readObject();
         this.accumulateFunctions = (Map<String, AccumulateFunction>) in.readObject();
-        this.factTemplates = (Map) in.readObject();
+        this.prototypes = (Map) in.readObject();
         this.globals = (Map<String, Type>) in.readObject();
         this.valid = in.readBoolean();
         this.needStreamMode = in.readBoolean();
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/java/org/drools/quarkus/test/TestableResource.java b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/java/org/drools/quarkus/test/TestableResource.java
index 2f2724fdf5..ce87188114 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/java/org/drools/quarkus/test/TestableResource.java
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/java/org/drools/quarkus/test/TestableResource.java
@@ -18,6 +18,15 @@
  */
 package org.drools.quarkus.test;
 
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Response;
 import org.kie.api.KieBase;
 import org.kie.api.definition.KiePackage;
 import org.kie.api.runtime.KieRuntimeBuilder;
@@ -25,15 +34,6 @@ import org.kie.api.runtime.KieSession;
 import org.kie.api.runtime.rule.FactHandle;
 import org.kie.api.time.SessionPseudoClock;
 
-import jakarta.inject.Inject;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.core.Response;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
 
@@ -100,7 +100,7 @@ public class TestableResource {
 
         List<String> pkgNames = kBase.getKiePackages().stream().map(KiePackage::getName).collect(Collectors.toList());
         assertThat(pkgNames)
-            .containsExactlyInAnyOrder("org.drools.quarkus.test","org.drools.drl","org.drools.dtable","org.drools.cep","org.drools.tms","org.drools.probe","org.drools.yaml");
+            .containsExactlyInAnyOrder("defaultpkg","org.drools.quarkus.test","org.drools.drl","org.drools.dtable","org.drools.cep","org.drools.tms","org.drools.probe","org.drools.yaml","org.drools.prototype");
         
         return Response.ok().build();
     }
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/META-INF/kmodule.xml b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/META-INF/kmodule.xml
index a090bae9e0..b5f9c8aec4 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/META-INF/kmodule.xml
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/META-INF/kmodule.xml
@@ -26,8 +26,11 @@
   <kbase name="canDrinkKBDTable" packages="org.drools.dtable">
     <ksession name="canDrinkKSDTable" />
   </kbase>
-  <kbase name="canDrinkKBDYaml" packages="org.drools.yaml">
-    <ksession name="canDrinkKSDYaml" />
+  <kbase name="canDrinkKBYaml" packages="org.drools.yaml">
+    <ksession name="canDrinkKSYaml" />
+  </kbase>
+  <kbase name="canDrinkKBPrototype" packages="org.drools.prototype" prototypes="allowed">
+    <ksession name="canDrinkKSPrototype" />
   </kbase>
   <kbase name="cepKB" packages="org.drools.cep" eventProcessingMode="stream">
     <ksession name="cepKS" clockType="pseudo"/>
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties
new file mode 100644
index 0000000000..effa45048b
--- /dev/null
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+drools.prototypes=allowed
\ No newline at end of file
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/org/drools/prototype/CanDrink.drl.yaml b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/org/drools/prototype/CanDrink.drl.yaml
new file mode 100755
index 0000000000..bd1b9be2a1
--- /dev/null
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/org/drools/prototype/CanDrink.drl.yaml
@@ -0,0 +1,22 @@
+name: org.drools.prototype
+rules:
+    - name: R1
+      when:
+          - given: Result
+            as: $r
+          - given: Person
+            as: $p
+            having:
+                - age >= 18
+      then: |
+          $r.value = $p.name + " can drink";
+    - name: R2
+      when:
+          - given: Result
+            as: $r
+          - given: Person
+            as: $p
+            having:
+                - age < 18
+      then: |
+          $r.value = $p.name + " can NOT drink";
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java b/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java
index 4a6806ccc0..96c380dd55 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java
@@ -18,18 +18,21 @@
  */
 package org.drools.quarkus.test;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 import io.quarkus.test.junit.QuarkusTest;
+import jakarta.inject.Inject;
 import org.junit.jupiter.api.Test;
 import org.kie.api.definition.KiePackage;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
 import org.kie.api.runtime.KieRuntimeBuilder;
 import org.kie.api.runtime.KieSession;
 
-import jakarta.inject.Inject;
-import java.util.List;
-import java.util.stream.Collectors;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
 
 @QuarkusTest
 public class RuntimeTest {
@@ -50,7 +53,7 @@ public class RuntimeTest {
 
     @Test
     public void testYamlEvaluation() {
-        testSimpleDrl(runtimeBuilder.newKieSession("canDrinkKSDYaml"), "org.drools.yaml");
+        testSimpleDrl(runtimeBuilder.newKieSession("canDrinkKSYaml"), "org.drools.yaml");
     }
 
     private void testSimpleDrl(KieSession ksession, String assetPackage) {
@@ -66,4 +69,23 @@ public class RuntimeTest {
 
         assertEquals("Mark can NOT drink", result.toString());
     }
+
+    @Test
+    public void testPrototypeEvaluation() {
+        KieSession ksession = runtimeBuilder.newKieSession("canDrinkKSPrototype");
+
+        PrototypeFact personFact = prototype("Person" ).asFact();
+        PrototypeFactInstance mark = personFact.newInstance();
+        mark.put("name", "Mark" );
+        mark.put("age", 17 );
+        ksession.insert(mark);
+
+        PrototypeFact resultFact = prototype( "Result" ).asFact();
+        PrototypeFactInstance result = resultFact.newInstance();
+        ksession.insert(result);
+
+        ksession.fireAllRules();
+
+        assertEquals("Mark can NOT drink", result.get("value"));
+    }
 }
diff --git a/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/DroolsQuarkusResourceUtils.java b/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/DroolsQuarkusResourceUtils.java
index 4aa6fee038..612dfeceb5 100644
--- a/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/DroolsQuarkusResourceUtils.java
+++ b/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/DroolsQuarkusResourceUtils.java
@@ -19,6 +19,16 @@
 package org.drools.quarkus.util.deployment;
 
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
 import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
 import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
 import io.quarkus.deployment.annotations.BuildProducer;
@@ -42,16 +52,6 @@ import org.kie.memorycompiler.JavaCompilerSettings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
 import static org.drools.util.Config.getConfig;
 import static org.kie.memorycompiler.KieMemoryCompiler.compileNoLoad;
 
@@ -93,6 +93,7 @@ public class DroolsQuarkusResourceUtils {
         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
         DroolsModelBuildContext context = QuarkusDroolsModelBuildContext.builder()
                 .withClassLoader(classLoader)
+                .withApplicationProperties(appPaths.getResourceFiles())
                 .withClassAvailabilityResolver(className -> classAvailabilityResolver(index, className))
                 .withAppPaths(appPaths)
                 .build();
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceAfterTest.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceAfterTest.java
index daee3e6fb6..b511beb341 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceAfterTest.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceAfterTest.java
@@ -22,21 +22,21 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import org.drools.base.facttemplates.Event;
 import org.drools.model.Global;
 import org.drools.model.Index;
 import org.drools.model.Model;
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeDSL;
-import org.drools.model.PrototypeVariable;
 import org.drools.model.Rule;
 import org.drools.model.Variable;
 import org.drools.model.impl.ModelImpl;
+import org.drools.model.prototype.PrototypeDSL;
+import org.drools.model.prototype.PrototypeVariable;
 import org.drools.reliability.test.util.TimeAmount;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeEventInstance;
 import org.kie.api.runtime.conf.ClockTypeOption;
 import org.kie.api.runtime.conf.PersistedSessionOption;
 
@@ -48,14 +48,13 @@ import static org.drools.model.DSL.globalOf;
 import static org.drools.model.DSL.not;
 import static org.drools.model.DSL.on;
 import static org.drools.model.PatternDSL.rule;
-import static org.drools.model.PrototypeDSL.protoPattern;
-import static org.drools.model.PrototypeDSL.variable;
-import static org.drools.model.PrototypeExpression.fixedValue;
-import static org.drools.model.PrototypeExpression.prototypeField;
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedEvent;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
+import static org.drools.model.prototype.PrototypeExpression.fixedValue;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
 import static org.drools.reliability.test.util.PrototypeUtils.DEFAULT_PROTOTYPE_NAME;
 import static org.drools.reliability.test.util.PrototypeUtils.SYNTHETIC_PROTOTYPE_NAME;
-import static org.drools.reliability.test.util.PrototypeUtils.getPrototype;
+import static org.drools.reliability.test.util.PrototypeUtils.getPrototypeEvent;
 import static org.drools.reliability.test.util.PrototypeUtils.processResults;
 
 @ExtendWith(BeforeAllMethodExtension.class)
@@ -68,7 +67,7 @@ class ReliabilityCepOnceAfterTest extends ReliabilityTestBasics {
      * These rules are created in the same way as OnceAfterDefinition in drools-ansible-rulebook-integration
      */
     private Model ruleModel() {
-        Prototype controlPrototype = getPrototype(SYNTHETIC_PROTOTYPE_NAME);
+        PrototypeEvent controlPrototype = getPrototypeEvent(SYNTHETIC_PROTOTYPE_NAME);
         PrototypeVariable controlVar1 = variable(controlPrototype, "c1");
         PrototypeVariable controlVar2 = variable(controlPrototype, "c2");
         PrototypeVariable controlVar3 = variable(controlPrototype, "c3");
@@ -94,20 +93,20 @@ class ReliabilityCepOnceAfterTest extends ReliabilityTestBasics {
         );
 
         // control rule (wrapping original event)
-        PrototypeVariable originalEventVariable = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m");
+        PrototypeVariable originalEventVariable = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m");
         rules.add(
                   rule(RULE_NAME + "_control").metadata(SYNTHETIC_RULE_TAG, true)
                           .build(
                                   guardedPattern(originalEventVariable),
                                   not(duplicateControlPattern(originalEventVariable)),
                                   on(originalEventVariable).execute((drools, event) -> {
-                                      Event controlEvent = createMapBasedEvent(controlPrototype);
-                                      controlEvent.set("sensu.host", event.get("sensu.host")); // groupByAttributes
-                                      controlEvent.set("sensu.process.type", event.get("sensu.process.type")); // groupByAttributes
-                                      controlEvent.set("drools_rule_name", RULE_NAME);
-                                      controlEvent.set("event", event);
-                                      controlEvent.set("once_after_time_window", "10 minutes");
-                                      controlEvent.set("events_in_window", 1);
+                                      PrototypeEventInstance controlEvent = controlPrototype.newInstance();
+                                      controlEvent.put("sensu.host", event.get("sensu.host")); // groupByAttributes
+                                      controlEvent.put("sensu.process.type", event.get("sensu.process.type")); // groupByAttributes
+                                      controlEvent.put("drools_rule_name", RULE_NAME);
+                                      controlEvent.put("event", event);
+                                      controlEvent.put("once_after_time_window", "10 minutes");
+                                      controlEvent.put("events_in_window", 1);
                                       drools.insert(controlEvent);
                                       drools.delete(event);
                                   })
@@ -122,13 +121,13 @@ class ReliabilityCepOnceAfterTest extends ReliabilityTestBasics {
                                   protoPattern(controlVar1).expr("drools_rule_name", Index.ConstraintType.EQUAL, RULE_NAME),
                                   not(protoPattern(controlVar2).expr("end_once_after", Index.ConstraintType.EQUAL, RULE_NAME)),
                                   on(controlVar1).execute((drools, c1) -> {
-                                      Event startControlEvent = createMapBasedEvent(controlPrototype)
+                                      PrototypeEventInstance startControlEvent = controlPrototype.newInstance()
                                               .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                      startControlEvent.set("start_once_after", RULE_NAME);
+                                      startControlEvent.put("start_once_after", RULE_NAME);
                                       drools.insert(startControlEvent);
 
-                                      Event endControlEvent = createMapBasedEvent(controlPrototype);
-                                      endControlEvent.set("end_once_after", RULE_NAME);
+                                      PrototypeEventInstance endControlEvent = controlPrototype.newInstance();
+                                      endControlEvent.put("end_once_after", RULE_NAME);
                                       drools.insert(endControlEvent);
                                   })
                           )
@@ -142,7 +141,7 @@ class ReliabilityCepOnceAfterTest extends ReliabilityTestBasics {
                                   guardedPattern(originalEventVariable),
                                   duplicateControlPattern,
                                   on(originalEventVariable, duplicateControlPattern.getFirstVariable()).execute((drools, event, control) -> {
-                                      control.set("events_in_window", ((int) control.get("events_in_window")) + 1);
+                                      control.put("events_in_window", ((int) control.get("events_in_window")) + 1);
                                       drools.delete(event);
                                   })
                           )
@@ -158,7 +157,7 @@ class ReliabilityCepOnceAfterTest extends ReliabilityTestBasics {
 
     // We group-by sensu.host and sensu.process.type
     private static PrototypeDSL.PrototypePatternDef duplicateControlPattern(PrototypeVariable originalEventVariable) {
-        return protoPattern(variable(getPrototype(SYNTHETIC_PROTOTYPE_NAME)))
+        return protoPattern(variable(getPrototypeEvent(SYNTHETIC_PROTOTYPE_NAME)))
                 .expr(prototypeField("sensu.host"), Index.ConstraintType.EQUAL, originalEventVariable, prototypeField("sensu.host")) // groupByAttributes
                 .expr(prototypeField("sensu.process.type"), Index.ConstraintType.EQUAL, originalEventVariable, prototypeField("sensu.process.type")) // groupByAttributes
                 .expr(prototypeField("drools_rule_name"), Index.ConstraintType.EQUAL, fixedValue(RULE_NAME));
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceWithinTest.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceWithinTest.java
index 5367eebdea..ec1ef9d23f 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceWithinTest.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepOnceWithinTest.java
@@ -22,22 +22,22 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import org.drools.base.facttemplates.Event;
 import org.drools.model.DroolsEntryPoint;
 import org.drools.model.Global;
 import org.drools.model.Index;
 import org.drools.model.Model;
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeDSL;
-import org.drools.model.PrototypeVariable;
 import org.drools.model.Rule;
 import org.drools.model.impl.ModelImpl;
-import org.drools.modelcompiler.facttemplate.HashMapEventImpl;
+import org.drools.model.prototype.PrototypeDSL;
+import org.drools.model.prototype.PrototypeVariable;
+import org.drools.model.prototype.impl.HashMapEventImpl;
 import org.drools.reliability.test.util.TimeAmount;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeEventInstance;
 import org.kie.api.runtime.conf.ClockTypeOption;
 import org.kie.api.runtime.conf.PersistedSessionOption;
 
@@ -47,14 +47,13 @@ import static org.drools.model.DSL.globalOf;
 import static org.drools.model.DSL.not;
 import static org.drools.model.DSL.on;
 import static org.drools.model.PatternDSL.rule;
-import static org.drools.model.PrototypeDSL.protoPattern;
-import static org.drools.model.PrototypeDSL.variable;
-import static org.drools.model.PrototypeExpression.fixedValue;
-import static org.drools.model.PrototypeExpression.prototypeField;
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedEvent;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
+import static org.drools.model.prototype.PrototypeExpression.fixedValue;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
 import static org.drools.reliability.test.util.PrototypeUtils.DEFAULT_PROTOTYPE_NAME;
 import static org.drools.reliability.test.util.PrototypeUtils.SYNTHETIC_PROTOTYPE_NAME;
-import static org.drools.reliability.test.util.PrototypeUtils.getPrototype;
+import static org.drools.reliability.test.util.PrototypeUtils.getPrototypeEvent;
 
 @ExtendWith(BeforeAllMethodExtension.class)
 class ReliabilityCepOnceWithinTest extends ReliabilityTestBasics {
@@ -66,24 +65,24 @@ class ReliabilityCepOnceWithinTest extends ReliabilityTestBasics {
      * These rules are created in the same way as OnceWithinDefinition in drools-ansible-rulebook-integration
      */
     private Model ruleModel() {
-        Prototype controlPrototype = getPrototype(SYNTHETIC_PROTOTYPE_NAME);
+        PrototypeEvent controlPrototype = getPrototypeEvent(SYNTHETIC_PROTOTYPE_NAME);
         Global<List> global = globalOf(List.class, "defaultpkg", "results");
 
         List<Rule> rules = new ArrayList<>();
 
         // main rule (match only once for grouped events within 10 minutes)
         TimeAmount timeAmount = TimeAmount.parseTimeAmount("10 minutes");
-        PrototypeVariable originalEventVariable = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m");
+        PrototypeVariable originalEventVariable = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m");
         rules.add(rule(RULE_NAME).metadata(RULE_TYPE_TAG, KEYWORD)
                           .build(
                                   guardedPattern(originalEventVariable),
                                   not(duplicateControlPattern(originalEventVariable)),
                                   on(originalEventVariable, global).execute((drools, event, globalResults) -> {
-                                      Event controlEvent = createMapBasedEvent(controlPrototype)
+                                      PrototypeEventInstance controlEvent = controlPrototype.newInstance()
                                               .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                      controlEvent.set("sensu.host", event.get("sensu.host")); // groupByAttributes
-                                      controlEvent.set("sensu.process.type", event.get("sensu.process.type")); // groupByAttributes
-                                      controlEvent.set("drools_rule_name", RULE_NAME);
+                                      controlEvent.put("sensu.host", event.get("sensu.host")); // groupByAttributes
+                                      controlEvent.put("sensu.process.type", event.get("sensu.process.type")); // groupByAttributes
+                                      controlEvent.put("drools_rule_name", RULE_NAME);
                                       drools.insert(controlEvent);
                                       globalResults.add(event);
                                       drools.delete(event);
@@ -110,7 +109,7 @@ class ReliabilityCepOnceWithinTest extends ReliabilityTestBasics {
 
     // We group-by sensu.host and sensu.process.type
     private static PrototypeDSL.PrototypePatternDef duplicateControlPattern(PrototypeVariable originalEventVariable) {
-        return protoPattern(variable(getPrototype(SYNTHETIC_PROTOTYPE_NAME)))
+        return protoPattern(variable(getPrototypeEvent(SYNTHETIC_PROTOTYPE_NAME)))
                 .expr(prototypeField("sensu.host"), Index.ConstraintType.EQUAL, originalEventVariable, prototypeField("sensu.host")) // groupByAttributes
                 .expr(prototypeField("sensu.process.type"), Index.ConstraintType.EQUAL, originalEventVariable, prototypeField("sensu.process.type")) // groupByAttributes
                 .expr(prototypeField("drools_rule_name"), Index.ConstraintType.EQUAL, fixedValue(RULE_NAME));
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimeWindowTest.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimeWindowTest.java
index e0e1bbf1b2..df5099e75e 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimeWindowTest.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimeWindowTest.java
@@ -25,9 +25,9 @@ import java.util.concurrent.TimeUnit;
 import org.drools.model.Global;
 import org.drools.model.Index;
 import org.drools.model.Model;
-import org.drools.model.PrototypeVariable;
 import org.drools.model.Rule;
 import org.drools.model.impl.ModelImpl;
+import org.drools.model.prototype.PrototypeVariable;
 import org.drools.reliability.test.util.TimeAmount;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -41,10 +41,10 @@ import static org.drools.model.DSL.after;
 import static org.drools.model.DSL.globalOf;
 import static org.drools.model.DSL.on;
 import static org.drools.model.PatternDSL.rule;
-import static org.drools.model.PrototypeDSL.protoPattern;
-import static org.drools.model.PrototypeDSL.variable;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
 import static org.drools.reliability.test.util.PrototypeUtils.DEFAULT_PROTOTYPE_NAME;
-import static org.drools.reliability.test.util.PrototypeUtils.getPrototype;
+import static org.drools.reliability.test.util.PrototypeUtils.getPrototypeEvent;
 
 @ExtendWith(BeforeAllMethodExtension.class)
 class ReliabilityCepTimeWindowTest extends ReliabilityTestBasics {
@@ -61,9 +61,9 @@ class ReliabilityCepTimeWindowTest extends ReliabilityTestBasics {
 
         // main rule (all events should be matched within +- 5 minutes each other)
         TimeAmount timeAmount = TimeAmount.parseTimeAmount("5 minutes");
-        PrototypeVariable var0 = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m_0");
-        PrototypeVariable var1 = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m_1");
-        PrototypeVariable var2 = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m_2");
+        PrototypeVariable var0 = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m_0");
+        PrototypeVariable var1 = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m_1");
+        PrototypeVariable var2 = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m_2");
         rules.add(
                   rule( RULE_NAME )
                     .build(
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimedOutTest.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimedOutTest.java
index f6fd3c37c8..ecb34ecbff 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimedOutTest.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityCepTimedOutTest.java
@@ -22,20 +22,20 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import org.drools.base.facttemplates.Event;
 import org.drools.model.Global;
 import org.drools.model.Index;
 import org.drools.model.Model;
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeVariable;
 import org.drools.model.Rule;
 import org.drools.model.Variable;
 import org.drools.model.impl.ModelImpl;
+import org.drools.model.prototype.PrototypeVariable;
 import org.drools.reliability.test.util.TimeAmount;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeEventInstance;
 import org.kie.api.runtime.conf.ClockTypeOption;
 import org.kie.api.runtime.conf.PersistedSessionOption;
 import org.kie.api.runtime.rule.RuleContext;
@@ -50,14 +50,13 @@ import static org.drools.model.DSL.not;
 import static org.drools.model.DSL.on;
 import static org.drools.model.PatternDSL.pattern;
 import static org.drools.model.PatternDSL.rule;
-import static org.drools.model.PrototypeDSL.protoPattern;
-import static org.drools.model.PrototypeDSL.variable;
-import static org.drools.model.PrototypeExpression.prototypeField;
-import static org.drools.model.PrototypeExpression.thisPrototype;
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedEvent;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
+import static org.drools.model.prototype.PrototypeExpression.thisPrototype;
 import static org.drools.reliability.test.util.PrototypeUtils.DEFAULT_PROTOTYPE_NAME;
 import static org.drools.reliability.test.util.PrototypeUtils.SYNTHETIC_PROTOTYPE_NAME;
-import static org.drools.reliability.test.util.PrototypeUtils.getPrototype;
+import static org.drools.reliability.test.util.PrototypeUtils.getPrototypeEvent;
 
 @ExtendWith(BeforeAllMethodExtension.class)
 class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
@@ -69,11 +68,11 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
      * These rules are created in the same way as TimedOutDefinition in drools-ansible-rulebook-integration
      */
     private Model ruleModel() {
-        Prototype controlPrototype = getPrototype(SYNTHETIC_PROTOTYPE_NAME);
+        PrototypeEvent controlPrototype = getPrototypeEvent(SYNTHETIC_PROTOTYPE_NAME);
         PrototypeVariable controlVar1 = variable(controlPrototype, "c1");
         PrototypeVariable controlVar2 = variable(controlPrototype, "c2");
         PrototypeVariable controlVar3 = variable(controlPrototype, "c3");
-        PrototypeVariable eventVar = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "e");
+        PrototypeVariable eventVar = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "e");
         Variable<Long> resultCount = declarationOf( Long.class, "count" );
         Global<List> global = globalOf(List.class, "defaultpkg", "results");
 
@@ -102,7 +101,7 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
 
         // sub-rule 0
         String subRuleName0 = rulePrefix + "0";
-        PrototypeVariable patternVariable0 = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m_0");
+        PrototypeVariable patternVariable0 = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m_0");
         rules.add(
                   rule( subRuleName0 ).metadata(SYNTHETIC_RULE_TAG, true)
                      .build(
@@ -111,11 +110,11 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
                              not( protoPattern(controlVar1)
                                      .expr( "rulename", Index.ConstraintType.EQUAL, subRuleName0 ) ),
                              on(patternVariable0).execute((drools, t1) -> {
-                                 Event controlEvent = createMapBasedEvent( controlPrototype )
+                                 PrototypeEventInstance controlEvent = controlPrototype.newInstance()
                                          .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                 controlEvent.set( "rulename", subRuleName0 );
-                                 controlEvent.set( "event", t1 );
-                                 controlEvent.set( "binding", ((RuleContext) drools).getMatch().getDeclarationIds().get(0) );
+                                 controlEvent.put("rulename", subRuleName0 );
+                                 controlEvent.put("event", t1 );
+                                 controlEvent.put("binding", ((RuleContext) drools).getMatch().getDeclarationIds().get(0) );
                                  drools.insert(controlEvent);
                              })
                      )
@@ -123,7 +122,7 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
 
         // sub-rule 1
         String subRuleName1 = rulePrefix + "1";
-        PrototypeVariable patternVariable1 = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m_1");
+        PrototypeVariable patternVariable1 = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m_1");
         rules.add(
                   rule( subRuleName1 ).metadata(SYNTHETIC_RULE_TAG, true)
                      .build(
@@ -132,11 +131,11 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
                              not( protoPattern(controlVar1)
                                      .expr( "rulename", Index.ConstraintType.EQUAL, subRuleName1 ) ),
                              on(patternVariable1).execute((drools, t1) -> {
-                                 Event controlEvent = createMapBasedEvent( controlPrototype )
+                                 PrototypeEventInstance controlEvent = controlPrototype.newInstance()
                                          .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                 controlEvent.set( "rulename", subRuleName1 );
-                                 controlEvent.set( "event", t1 );
-                                 controlEvent.set( "binding", ((RuleContext) drools).getMatch().getDeclarationIds().get(0) );
+                                 controlEvent.put("rulename", subRuleName1 );
+                                 controlEvent.put("event", t1 );
+                                 controlEvent.put("binding", ((RuleContext) drools).getMatch().getDeclarationIds().get(0) );
                                  drools.insert(controlEvent);
                              })
                      )
@@ -144,7 +143,7 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
 
         // sub-rule 2
         String subRuleName2 = rulePrefix + "2";
-        PrototypeVariable patternVariable2 = variable(getPrototype(DEFAULT_PROTOTYPE_NAME), "m_2");
+        PrototypeVariable patternVariable2 = variable(getPrototypeEvent(DEFAULT_PROTOTYPE_NAME), "m_2");
         rules.add(
                   rule( subRuleName2 ).metadata(SYNTHETIC_RULE_TAG, true)
                      .build(
@@ -153,11 +152,11 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
                              not( protoPattern(controlVar1)
                                      .expr( "rulename", Index.ConstraintType.EQUAL, subRuleName2 ) ),
                              on(patternVariable2).execute((drools, t1) -> {
-                                 Event controlEvent = createMapBasedEvent( controlPrototype )
+                                 PrototypeEventInstance controlEvent = controlPrototype.newInstance()
                                          .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                 controlEvent.set( "rulename", subRuleName2 );
-                                 controlEvent.set( "event", t1 );
-                                 controlEvent.set( "binding", ((RuleContext) drools).getMatch().getDeclarationIds().get(0) );
+                                 controlEvent.put("rulename", subRuleName2 );
+                                 controlEvent.put("event", t1 );
+                                 controlEvent.put("binding", ((RuleContext) drools).getMatch().getDeclarationIds().get(0) );
                                  drools.insert(controlEvent);
                              })
                       )
@@ -170,11 +169,11 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
                               not( protoPattern(controlVar1).expr( "rulename", Index.ConstraintType.EQUAL, startTag ) ),
                               protoPattern(controlVar2).expr( p -> ((String)p.get("rulename")).startsWith(rulePrefix) ),
                               on(controlVar2).execute((drools, firstEvent) -> {
-                                  Event controlEvent = createMapBasedEvent( controlPrototype )
+                                  PrototypeEventInstance controlEvent = controlPrototype.newInstance()
                                           .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                  controlEvent.set( "rulename", startTag );
-                                  controlEvent.set( "event", firstEvent.get("event") );
-                                  controlEvent.set( "binding", firstEvent.get("binding") );
+                                  controlEvent.put("rulename", startTag );
+                                  controlEvent.put("event", firstEvent.get("event") );
+                                  controlEvent.put("binding", firstEvent.get("binding") );
                                   drools.insert(controlEvent);
                               })
                       )
@@ -189,9 +188,9 @@ class ReliabilityCepTimedOutTest extends ReliabilityTestBasics {
                                       accFunction(org.drools.core.base.accumulators.CountAccumulateFunction::new).as(resultCount)),
                               pattern(resultCount).expr(count -> count == 3),
                               on(resultCount).execute((drools, count) -> {
-                                  Event controlEvent = createMapBasedEvent( controlPrototype )
+                                  PrototypeEventInstance controlEvent = controlPrototype.newInstance()
                                           .withExpiration(timeAmount.getAmount(), timeAmount.getTimeUnit());
-                                  controlEvent.set( "rulename", endTag );
+                                  controlEvent.put("rulename", endTag );
                                   drools.insert(controlEvent);
                               })
                       )
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityTestBasics.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityTestBasics.java
index 4864e9bb3b..cefcf88e4d 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityTestBasics.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/ReliabilityTestBasics.java
@@ -18,7 +18,14 @@
  */
 package org.drools.reliability.test;
 
-import org.drools.base.facttemplates.Event;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
 import org.drools.core.ClassObjectFilter;
 import org.drools.kiesession.session.StatefulKnowledgeSessionImpl;
 import org.drools.model.Model;
@@ -41,6 +48,7 @@ import org.kie.api.KieServices;
 import org.kie.api.conf.KieBaseOption;
 import org.kie.api.conf.Option;
 import org.kie.api.io.ResourceType;
+import org.kie.api.prototype.PrototypeEventInstance;
 import org.kie.api.runtime.KieSession;
 import org.kie.api.runtime.KieSessionConfiguration;
 import org.kie.api.runtime.conf.KieSessionOption;
@@ -52,14 +60,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.test.domain.Person;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Stream;
-
 import static org.drools.reliability.infinispan.InfinispanStorageManagerFactory.INFINISPAN_STORAGE_MARSHALLER;
 import static org.drools.reliability.infinispan.InfinispanStorageManagerFactory.INFINISPAN_STORAGE_MODE;
 import static org.drools.reliability.test.util.PrototypeUtils.createEvent;
@@ -502,27 +502,27 @@ public abstract class ReliabilityTestBasics {
     }
 
     private void insertSensuEvent(String host, String type) {
-        Event sensu = createEvent();
-        sensu.set("sensu.host", host);
-        sensu.set("sensu.process.type", type);
+        PrototypeEventInstance sensu = createEvent();
+        sensu.put("sensu.host", host);
+        sensu.put("sensu.process.type", type);
         sessions.get(0).insert(sensu);
     }
 
     protected void insertMatchingSensuProcessStatusEvent(String status) {
-        Event sensu = createEvent();
-        sensu.set("sensu.process.status", status);
+        PrototypeEventInstance sensu = createEvent();
+        sensu.put("sensu.process.status", status);
         sessions.get(0).insert(sensu);
     }
 
     protected void insertMatchingPingTimeoutEvent(boolean timeout) {
-        Event ping = createEvent();
-        ping.set("ping.timeout", timeout);
+        PrototypeEventInstance ping = createEvent();
+        ping.put("ping.timeout", timeout);
         sessions.get(0).insert(ping);
     }
 
     protected void insertMatchingSensuStoragePercentEvent(int percent) {
-        Event sensu = createEvent();
-        sensu.set("sensu.storage.percent", percent);
+        PrototypeEventInstance sensu = createEvent();
+        sensu.put("sensu.storage.percent", percent);
         sessions.get(0).insert(sensu);
     }
 }
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/proto/HashMapEventImplAdaptor.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/proto/HashMapEventImplAdaptor.java
index 8ebbf46d99..dfa7386f23 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/proto/HashMapEventImplAdaptor.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/proto/HashMapEventImplAdaptor.java
@@ -21,15 +21,14 @@ package org.drools.reliability.test.proto;
 import java.util.Map;
 import java.util.UUID;
 
-import org.drools.modelcompiler.facttemplate.HashMapEventImpl;
+import org.drools.model.prototype.impl.HashMapEventImpl;
 import org.drools.reliability.infinispan.proto.ProtoStreamUtils;
 import org.infinispan.protostream.annotations.ProtoAdapter;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 import org.infinispan.protostream.types.protobuf.AnySchema;
 
-import static org.drools.modelcompiler.facttemplate.FactFactory.prototypeToFactTemplate;
-import static org.drools.reliability.test.util.PrototypeUtils.getPrototype;
+import static org.drools.reliability.test.util.PrototypeUtils.getPrototypeEvent;
 
 /**
  * This adopter resides in test module, because main drools-reliability-infinispan module does not have dependency on drools-model-compiler module.
@@ -40,7 +39,7 @@ public class HashMapEventImplAdaptor {
     @ProtoFactory
     HashMapEventImpl create(String uuid, String factTemplate, AnySchema.Any valuesMapObject, long timestamp, long expiration) {
         Map<String, Object> valuesMap = (Map<String, Object>) ProtoStreamUtils.fromAnySchema(valuesMapObject);
-        return new HashMapEventImpl(UUID.fromString(uuid), prototypeToFactTemplate(getPrototype(factTemplate)), valuesMap, timestamp, expiration);
+        return new HashMapEventImpl(UUID.fromString(uuid), getPrototypeEvent(factTemplate), valuesMap, timestamp, expiration);
     }
 
     @ProtoField(1)
@@ -50,13 +49,12 @@ public class HashMapEventImplAdaptor {
 
     @ProtoField(2)
     String getFactTemplate(HashMapEventImpl event) {
-        return event.getFactTemplate().getName();
+        return event.getPrototype().getName();
     }
 
     @ProtoField(number = 3, required = true)
     AnySchema.Any getValuesMapObject(HashMapEventImpl event) {
-        Map<String, Object> map = event.asMap();
-        return ProtoStreamUtils.toAnySchema(map);
+        return ProtoStreamUtils.toAnySchema(event);
     }
 
     @ProtoField(number = 4, defaultValue = "-1")
diff --git a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/util/PrototypeUtils.java b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/util/PrototypeUtils.java
index 0af1e11917..fcca0e35a3 100644
--- a/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/util/PrototypeUtils.java
+++ b/drools-reliability/drools-reliability-tests/src/test/java/org/drools/reliability/test/util/PrototypeUtils.java
@@ -23,38 +23,42 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import org.drools.base.facttemplates.Event;
-import org.drools.model.Prototype;
-import org.drools.model.PrototypeDSL;
-import org.drools.model.PrototypeFact;
+import org.kie.api.prototype.PrototypeEvent;
+import org.kie.api.prototype.PrototypeEventInstance;
+import org.kie.api.prototype.PrototypeFact;
 
-import static org.drools.modelcompiler.facttemplate.FactFactory.createMapBasedEvent;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
 
 public class PrototypeUtils {
 
     public static final String DEFAULT_PROTOTYPE_NAME = "DROOLS_PROTOTYPE";
     public static final String SYNTHETIC_PROTOTYPE_NAME = "DROOLS_SYNTHETIC_PROTOTYPE";
 
-    private static final Map<String, Prototype> prototypes = new HashMap<>();
+    private static final Map<String, PrototypeFact> prototypeFacts = new HashMap<>();
+    private static final Map<String, PrototypeEvent> prototypeEvents = new HashMap<>();
 
     private PrototypeUtils() {
         // It is not allowed to create instances of util classes.
     }
 
-    public static Event createControlEvent() {
-        return createMapBasedEvent(getPrototype(SYNTHETIC_PROTOTYPE_NAME));
+    public static PrototypeEventInstance createControlEvent() {
+        return getPrototypeEvent(SYNTHETIC_PROTOTYPE_NAME).newInstance();
     }
 
-    public static Prototype getPrototype(String name) {
-        return prototypes.computeIfAbsent(name, PrototypeDSL::prototype);
+    public static PrototypeFact getPrototypeFact(String name) {
+        return prototypeFacts.computeIfAbsent(name, n -> prototype(n).asFact());
     }
 
-    public static void processResults(List<Object> globalResults, List<Event> controlResults) {
-        List<Object> events = controlResults.stream().map(r -> ((PrototypeFact) r).get("event")).collect(Collectors.toList());
+    public static PrototypeEvent getPrototypeEvent(String name) {
+        return prototypeEvents.computeIfAbsent(name, n -> prototype(n).asEvent());
+    }
+
+    public static void processResults(List<Object> globalResults, List<PrototypeEventInstance> controlResults) {
+        List<Object> events = controlResults.stream().map(r -> r.get("event")).collect(Collectors.toList());
         globalResults.addAll(events);
     }
 
-    public static Event createEvent() {
-        return createMapBasedEvent(getPrototype(DEFAULT_PROTOTYPE_NAME));
+    public static PrototypeEventInstance createEvent() {
+        return getPrototypeEvent(DEFAULT_PROTOTYPE_NAME).newInstance();
     }
 }
diff --git a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/conf/KnowledgeBaseConfigurationTest.java b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/conf/KnowledgeBaseConfigurationTest.java
index e11b772569..37a3d20a34 100644
--- a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/conf/KnowledgeBaseConfigurationTest.java
+++ b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/conf/KnowledgeBaseConfigurationTest.java
@@ -26,6 +26,7 @@ import org.kie.api.KieServices;
 import org.kie.api.conf.BetaRangeIndexOption;
 import org.kie.api.conf.EqualityBehaviorOption;
 import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.conf.RemoveIdentitiesOption;
 import org.kie.api.conf.SequentialOption;
 import org.kie.api.runtime.rule.ConsequenceExceptionHandler;
@@ -215,6 +216,25 @@ public class KnowledgeBaseConfigurationTest {
         // checking the string based getProperty() method
         assertThat(config.getProperty(EqualityBehaviorOption.PROPERTY_NAME)).isEqualTo("identity");
     }
+
+    @Test
+    public void testPrototypesConfiguration() {
+        // setting the option using the type safe method
+        config.setOption(PrototypesOption.ALLOWED);
+
+        // checking the type safe getOption() method
+        assertThat(config.getOption(PrototypesOption.KEY)).isEqualTo(PrototypesOption.ALLOWED);
+        // checking the string based getProperty() method
+        assertThat(config.getProperty(PrototypesOption.PROPERTY_NAME)).isEqualTo("allowed");
+
+        // setting the options using the string based setProperty() method
+        config.setProperty( PrototypesOption.PROPERTY_NAME, "disabled" );
+
+        // checking the type safe getOption() method
+        assertThat(config.getOption(PrototypesOption.KEY)).isEqualTo(PrototypesOption.DISABLED);
+        // checking the string based getProperty() method
+        assertThat(config.getProperty(PrototypesOption.PROPERTY_NAME)).isEqualTo("disabled");
+    }
     
     @Test
     public void testSequentialAgendaConfiguration() {
diff --git a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/Misc2Test.java b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/Misc2Test.java
index 703589b82d..908566b6ef 100644
--- a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/Misc2Test.java
+++ b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/Misc2Test.java
@@ -57,10 +57,6 @@ import org.drools.core.common.Memory;
 import org.drools.core.common.NodeMemories;
 import org.drools.base.definitions.InternalKnowledgePackage;
 import org.drools.base.definitions.rule.impl.RuleImpl;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateImpl;
-import org.drools.base.facttemplates.FieldTemplate;
-import org.drools.base.facttemplates.FieldTemplateImpl;
 import org.drools.core.impl.InternalRuleBase;
 import org.drools.core.reteoo.CoreComponentFactory;
 import org.drools.core.reteoo.LeftInputAdapterNode;
@@ -6556,31 +6552,6 @@ public class Misc2Test {
         assertThat(list).isEqualTo(Arrays.asList(42, 99));
     }
 
-    @Test
-    public void testFactTemplates() {
-        // DROOLS-600
-        String drl = "package com.testfacttemplate;" +
-                     " rule \"test rule\" " +
-                     " dialect \"mvel\" " +
-                     " when " +
-                     " $test : TestFactTemplate( status == 1 ) " +
-                     " then " +
-                     " System.out.println( \"Hello World\" ); " +
-                     " end ";
-
-        InternalKnowledgePackage kPackage = CoreComponentFactory.get().createKnowledgePackage( "com.testfacttemplate" );
-        FieldTemplate fieldTemplate = new FieldTemplateImpl( "status", Integer.class );
-        FactTemplate factTemplate = new FactTemplateImpl(kPackage, "TestFactTemplate", fieldTemplate);
-
-        KnowledgeBuilderImpl kBuilder = new KnowledgeBuilderImpl(kPackage );
-        StringReader rule = new StringReader( drl );
-        try {
-            kBuilder.addPackageFromDrl(rule);
-        } catch (Exception e) {
-            throw new RuntimeException( e );
-        }
-    }
-
     @Test
     public void testBitwiseOperator() {
         // DROOLS-585
diff --git a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/rule/PatternTest.java b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/rule/PatternTest.java
index 1a4538d18e..1b5a5da372 100644
--- a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/rule/PatternTest.java
+++ b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/rule/PatternTest.java
@@ -19,63 +19,49 @@
 package org.drools.mvel.rule;
 
 import org.drools.base.base.ClassObjectType;
-import org.drools.base.definitions.InternalKnowledgePackage;
-import org.drools.base.facttemplates.Fact;
-import org.drools.base.facttemplates.FactTemplate;
-import org.drools.base.facttemplates.FactTemplateImpl;
-import org.drools.base.facttemplates.FactTemplateObjectType;
-import org.drools.base.facttemplates.FieldTemplate;
-import org.drools.base.facttemplates.FieldTemplateImpl;
-import org.drools.core.reteoo.CoreComponentFactory;
+import org.drools.base.base.ObjectType;
+import org.drools.base.prototype.PrototypeObjectType;
 import org.drools.base.rule.Declaration;
 import org.drools.base.rule.Pattern;
 import org.drools.base.rule.accessor.ReadAccessor;
-import org.drools.base.base.ObjectType;
 import org.drools.core.test.model.Cheese;
 import org.junit.Test;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
 
 public class PatternTest {
 
     @Test
-    public void testDeclarationsObjectType() throws Exception {
+    public void testDeclarationsObjectType() {
         final ObjectType type = new ClassObjectType( Cheese.class );
-        final Pattern col = new Pattern( 0,
-                                       type,
-                                       "foo" );
+        final Pattern col = new Pattern( 0, type, "foo" );
         final Declaration dec = col.getDeclaration();
         final ReadAccessor ext = dec.getExtractor();
         assertThat(ext.getExtractToClass()).isEqualTo(Cheese.class);
 
-        final Cheese stilton = new Cheese( "stilton",
-                                           42 );
+        final Cheese stilton = new Cheese( "stilton", 42 );
 
         assertThat(dec.getValue(null, stilton)).isEqualTo(stilton);
 
     }
 
     @Test
-    public void testDeclarationsFactTemplate() throws Exception {
-
-        InternalKnowledgePackage pkg = CoreComponentFactory.get().createKnowledgePackage( "org.store" );
-        final FieldTemplate cheeseName = new FieldTemplateImpl( "name", String.class );
-        final FieldTemplate cheesePrice = new FieldTemplateImpl( "price", Integer.class );
-        final FieldTemplate[] fields = new FieldTemplate[]{cheeseName, cheesePrice};
-        final FactTemplate cheese = new FactTemplateImpl( pkg, "Cheese", fields );
+    public void testDeclarationsPrototype() {
+        PrototypeFact cheese = prototype("org.store.Cheese").withField("name", String.class).withField("price", Integer.class).asFact();
 
-        final ObjectType type = new FactTemplateObjectType( cheese );
+        final ObjectType type = new PrototypeObjectType(cheese );
 
-        final Pattern col = new Pattern( 0,
-                                       type,
-                                       "foo" );
+        final Pattern col = new Pattern( 0, type, "foo" );
         final Declaration dec = col.getDeclaration();
         final ReadAccessor ext = dec.getExtractor();
-        assertThat(ext.getExtractToClass()).isEqualTo(Fact.class);
+        assertThat(ext.getExtractToClass()).isEqualTo(PrototypeFactInstance.class);
 
-        final Fact stilton = cheese.createFact();
-        stilton.set( "name", "stilton" );
-        stilton.set( "price", Integer.valueOf( 200 ) );
+        PrototypeFactInstance stilton = cheese.newInstance();
+        stilton.put("name", "stilton" );
+        stilton.put("price", Integer.valueOf(200 ) );
 
         assertThat(dec.getValue(null, stilton)).isEqualTo(stilton);
     }
diff --git a/drools-traits/src/main/java/org/drools/traits/core/definitions/impl/TraitKnowledgePackageImpl.java b/drools-traits/src/main/java/org/drools/traits/core/definitions/impl/TraitKnowledgePackageImpl.java
index c7c6c392a7..65c0119297 100644
--- a/drools-traits/src/main/java/org/drools/traits/core/definitions/impl/TraitKnowledgePackageImpl.java
+++ b/drools-traits/src/main/java/org/drools/traits/core/definitions/impl/TraitKnowledgePackageImpl.java
@@ -103,7 +103,7 @@ public class TraitKnowledgePackageImpl extends MVELKnowledgePackageImpl {
             out.writeObject(this.staticImports);
             out.writeObject(this.functions);
             out.writeObject(this.accumulateFunctions);
-            out.writeObject(this.factTemplates);
+            out.writeObject(this.prototypes);
             out.writeObject(this.globals);
             out.writeBoolean(this.valid);
             out.writeBoolean(this.needStreamMode);
@@ -141,7 +141,7 @@ public class TraitKnowledgePackageImpl extends MVELKnowledgePackageImpl {
         this.staticImports = (Set) in.readObject();
         this.functions = (Map<String, Function>) in.readObject();
         this.accumulateFunctions = (Map<String, AccumulateFunction>) in.readObject();
-        this.factTemplates = (Map) in.readObject();
+        this.prototypes = (Map) in.readObject();
         this.globals = (Map<String, Type>) in.readObject();
         this.valid = in.readBoolean();
         this.needStreamMode = in.readBoolean();
diff --git a/drools-xml-support/src/main/java/org/drools/xml/support/converters/KBaseConverter.java b/drools-xml-support/src/main/java/org/drools/xml/support/converters/KBaseConverter.java
index 6b157916c3..22c6b1c3e4 100644
--- a/drools-xml-support/src/main/java/org/drools/xml/support/converters/KBaseConverter.java
+++ b/drools-xml-support/src/main/java/org/drools/xml/support/converters/KBaseConverter.java
@@ -34,6 +34,7 @@ import org.kie.api.conf.DeclarativeAgendaOption;
 import org.kie.api.conf.EqualityBehaviorOption;
 import org.kie.api.conf.EventProcessingOption;
 import org.kie.api.conf.KieBaseMutabilityOption;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.conf.SequentialOption;
 import org.kie.api.conf.SessionsPoolOption;
 
@@ -54,6 +55,9 @@ public class KBaseConverter extends AbstractXStreamConverter {
         if ( kBase.getEventProcessingMode() != null ) {
             writer.addAttribute( "eventProcessingMode", kBase.getEventProcessingMode().getMode() );
         }
+        if ( kBase.getPrototypes() != null ) {
+            writer.addAttribute( "prototypes", kBase.getPrototypes().toString().toLowerCase() );
+        }
         if ( kBase.getEqualsBehavior() != null ) {
             writer.addAttribute( "equalsBehavior", kBase.getEqualsBehavior().toString().toLowerCase() );
         }
@@ -133,6 +137,11 @@ public class KBaseConverter extends AbstractXStreamConverter {
             kBase.setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( eventMode ) );
         }
 
+        String prototypes = reader.getAttribute( "prototypes" );
+        if ( prototypes != null ) {
+            kBase.setPrototypes( PrototypesOption.determinePrototypesOption(prototypes) );
+        }
+
         String equalsBehavior = reader.getAttribute( "equalsBehavior" );
         if ( equalsBehavior != null ) {
             kBase.setEqualsBehavior( EqualityBehaviorOption.determineEqualityBehavior( equalsBehavior ) );
diff --git a/kie-api/src/main/java/org/kie/api/builder/model/KieBaseModel.java b/kie-api/src/main/java/org/kie/api/builder/model/KieBaseModel.java
index 6898c2fc6c..e39e2d90a0 100644
--- a/kie-api/src/main/java/org/kie/api/builder/model/KieBaseModel.java
+++ b/kie-api/src/main/java/org/kie/api/builder/model/KieBaseModel.java
@@ -27,6 +27,7 @@ import org.kie.api.conf.DeclarativeAgendaOption;
 import org.kie.api.conf.EqualityBehaviorOption;
 import org.kie.api.conf.EventProcessingOption;
 import org.kie.api.conf.KieBaseMutabilityOption;
+import org.kie.api.conf.PrototypesOption;
 import org.kie.api.conf.SequentialOption;
 import org.kie.api.conf.SessionsPoolOption;
 
@@ -110,6 +111,17 @@ public interface KieBaseModel {
      */
     KieBaseModel setEqualsBehavior(EqualityBehaviorOption equalsBehaviour);
 
+    /**
+     * Sets the PrototypesOption for this KieBaseModel.
... 382 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org