You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2022/02/23 13:20:30 UTC

[unomi] branch master updated: UNOMI-486 JSON Schema GraphQL integration (#387)

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

shuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/master by this push:
     new 4802e8e  UNOMI-486 JSON Schema GraphQL integration (#387)
4802e8e is described below

commit 4802e8e3c6b21abfb8c79c442e8c24226edd0ae6
Author: Serge Huber <sh...@jahia.com>
AuthorDate: Wed Feb 23 14:20:24 2022 +0100

    UNOMI-486 JSON Schema GraphQL integration (#387)
    
    * JSON Schema GraphQL integration
    
    * JSON Schema GraphQL integration
    - Fix for integration tests
    - Bug fix in event type name registration
    - Add form event type definition
    
    * UNOMI-486
    - Rename property type keyword to Unomi property type keyword
    - Allow null in itemId JSON schema.
    
    * UNOMI-486
    - Corrections on integration tests to fix problems
    - Added new login event type definition (not complete yet)
    - Activated event validation
---
 .../main/java/org/apache/unomi/api/EventType.java  |  73 ------
 .../main/java/org/apache/unomi/api/SchemaType.java |  60 -----
 .../json/JSONArrayType.java}                       |  19 +-
 .../json/JSONBooleanType.java}                     |  20 +-
 .../json/JSONEnumType.java}                        |  20 +-
 .../json/JSONIntegerType.java}                     |  20 +-
 .../json/JSONNullType.java}                        |  20 +-
 .../json/JSONNumberType.java}                      |  20 +-
 .../unomi/api/schema/json/JSONObjectType.java      |  52 ++++
 .../apache/unomi/api/schema/json/JSONSchema.java   | 107 +++++++++
 .../json/JSONStringType.java}                      |  20 +-
 .../org/apache/unomi/api/schema/json/JSONType.java | 111 +++++++++
 .../unomi/api/schema/json/JSONTypeFactory.java     |  91 +++++++
 .../apache/unomi/api/services/EventService.java    |  16 +-
 .../unomi/api/services/EventTypeRegistry.java      |  59 -----
 .../apache/unomi/api/services/SchemaRegistry.java  |  11 +-
 .../org/apache/unomi/api/utils/ParserHelper.java   |   2 +-
 .../graphql/schema/GraphQLSchemaProvider.java      | 198 +++++++++++-----
 .../unomi/graphql/schema/GraphQLSchemaUpdater.java |  10 +-
 .../unomi/graphql/schema/PropertyFilterUtils.java  |  26 +-
 .../types/resolvers/CDPEventInterfaceResolver.java |  12 +-
 .../test/java/org/apache/unomi/itests/BaseIT.java  |   6 +
 .../test/java/org/apache/unomi/itests/BasicIT.java |   4 +-
 .../org/apache/unomi/itests/ContextServletIT.java  | 108 +++------
 .../schemas/events/float-property-type.json        |  22 ++
 .../resources/schemas/events/test-event-type.json  |  13 +
 .../unomi/rest/endpoints/EventServiceEndpoint.java |  12 -
 .../services/impl/events/EventServiceImpl.java     |  19 +-
 .../impl/events/EventTypeRegistryImpl.java         | 261 ---------------------
 .../services/impl/schemas/SchemaRegistryImpl.java  | 106 ++++++---
 ...eKeyword.java => UnomiPropertyTypeKeyword.java} |   8 +-
 .../resources/META-INF/cxs/schemas/condition.json  |   2 +-
 .../META-INF/cxs/schemas/conditiontype.json        |   6 +-
 .../resources/META-INF/cxs/schemas/consent.json    |   2 +-
 .../META-INF/cxs/schemas/consentType.json          |   2 +-
 .../resources/META-INF/cxs/schemas/customitem.json |   4 +-
 .../META-INF/cxs/schemas/customitems/page.json     |  13 +-
 .../META-INF/cxs/schemas/customitems/site.json     |  11 +-
 .../main/resources/META-INF/cxs/schemas/event.json |   4 +-
 .../cxs/schemas/events/{view.json => form.json}    |  19 +-
 .../cxs/schemas/events/{view.json => login.json}   |  20 +-
 .../META-INF/cxs/schemas/events/modifyConsent.json |  22 +-
 .../META-INF/cxs/schemas/events/view.json          |  17 +-
 .../main/resources/META-INF/cxs/schemas/goal.json  |   8 +-
 .../main/resources/META-INF/cxs/schemas/item.json  |   4 +-
 .../resources/META-INF/cxs/schemas/metadata.json   |   2 +-
 .../META-INF/cxs/schemas/metadataitem.json         |   6 +-
 .../resources/META-INF/cxs/schemas/parameter.json  |   2 +-
 .../resources/META-INF/cxs/schemas/profile.json    |   4 +-
 .../resources/META-INF/cxs/schemas/session.json    |   6 +-
 .../META-INF/cxs/schemas/timestampeditem.json      |   4 +-
 .../META-INF/cxs/schemas/values/boolean.json       |   2 +-
 .../META-INF/cxs/schemas/values/date.json          |   2 +-
 .../META-INF/cxs/schemas/values/email.json         |   2 +-
 .../META-INF/cxs/schemas/values/integer.json       |   2 +-
 .../META-INF/cxs/schemas/values/long.json          |   2 +-
 .../resources/META-INF/cxs/schemas/values/set.json |   2 +-
 .../META-INF/cxs/schemas/values/string.json        |   2 +-
 .../resources/OSGI-INF/blueprint/blueprint.xml     |   7 -
 59 files changed, 847 insertions(+), 858 deletions(-)

diff --git a/api/src/main/java/org/apache/unomi/api/EventType.java b/api/src/main/java/org/apache/unomi/api/EventType.java
deleted file mode 100644
index 5ae05b8..0000000
--- a/api/src/main/java/org/apache/unomi/api/EventType.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.apache.unomi.api;
-
-import java.util.Set;
-
-/**
- * An event type definition, used to define the structure of accepted events
- */
-public class EventType implements PluginType {
-
-    private String type;
-
-    private Set<PropertyType> propertyTypes;
-
-    private long pluginId;
-
-    public EventType() {
-    }
-
-    public EventType(String type, Set<PropertyType> propertyTypes, long pluginId) {
-        this.type = type;
-        this.propertyTypes = propertyTypes;
-        this.pluginId = pluginId;
-    }
-
-    public String getType() {
-        return type;
-    }
-
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    public Set<PropertyType> getPropertyTypes() {
-        return propertyTypes;
-    }
-
-    public void setPropertyTypes(Set<PropertyType> propertyTypes) {
-        this.propertyTypes = propertyTypes;
-    }
-
-    @Override
-    public long getPluginId() {
-        return pluginId;
-    }
-
-    @Override
-    public void setPluginId(long pluginId) {
-        this.pluginId = pluginId;
-    }
-
-    public void merge(final EventType source) {
-        if (source == null || source.getPropertyTypes() == null || source.getPropertyTypes().isEmpty()) {
-            return;
-        }
-        this.propertyTypes.addAll(source.getPropertyTypes());
-    }
-}
diff --git a/api/src/main/java/org/apache/unomi/api/SchemaType.java b/api/src/main/java/org/apache/unomi/api/SchemaType.java
deleted file mode 100644
index a3bd37a..0000000
--- a/api/src/main/java/org/apache/unomi/api/SchemaType.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.unomi.api;
-
-import java.util.Map;
-
-public class SchemaType implements PluginType {
-
-    private transient long pluginId;
-    private String schemaId;
-    private String target;
-    private Map<String,Object> schemaTree;
-
-    public long getPluginId() {
-        return pluginId;
-    }
-
-    public void setPluginId(long pluginId) {
-        this.pluginId = pluginId;
-    }
-
-    public String getSchemaId() {
-        return schemaId;
-    }
-
-    public void setSchemaId(String schemaId) {
-        this.schemaId = schemaId;
-    }
-
-    public String getTarget() {
-        return target;
-    }
-
-    public void setTarget(String target) {
-        this.target = target;
-    }
-
-    public Map<String, Object> getSchemaTree() {
-        return schemaTree;
-    }
-
-    public void setSchemaTree(Map<String, Object> schemaTree) {
-        this.schemaTree = schemaTree;
-    }
-}
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONArrayType.java
similarity index 66%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONArrayType.java
index 03a234e..add106d 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONArrayType.java
@@ -14,19 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
-
-import org.apache.unomi.api.SchemaType;
+import org.apache.unomi.api.services.SchemaRegistry;
 
 import java.util.List;
+import java.util.Map;
 
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
+public class JSONArrayType extends JSONType {
 
-    List<SchemaType> getTargetSchemas(String target);
+    List<JSONType> items;
+    JSONType contains;
 
+    public JSONArrayType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("array");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONBooleanType.java
similarity index 67%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONBooleanType.java
index 03a234e..cfaa734 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONBooleanType.java
@@ -14,19 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
+import org.apache.unomi.api.services.SchemaRegistry;
 
-import org.apache.unomi.api.SchemaType;
-
-import java.util.List;
-
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
-
-    List<SchemaType> getTargetSchemas(String target);
+import java.util.Map;
 
+public class JSONBooleanType extends JSONType {
+    public JSONBooleanType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("boolean");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONEnumType.java
similarity index 68%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONEnumType.java
index 03a234e..d2e18a0 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONEnumType.java
@@ -14,19 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
+import org.apache.unomi.api.services.SchemaRegistry;
 
-import org.apache.unomi.api.SchemaType;
-
-import java.util.List;
-
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
-
-    List<SchemaType> getTargetSchemas(String target);
+import java.util.Map;
 
+public class JSONEnumType extends JSONType {
+    public JSONEnumType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("enum");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONIntegerType.java
similarity index 67%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONIntegerType.java
index 03a234e..6aa9a32 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONIntegerType.java
@@ -14,19 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
+import org.apache.unomi.api.services.SchemaRegistry;
 
-import org.apache.unomi.api.SchemaType;
-
-import java.util.List;
-
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
-
-    List<SchemaType> getTargetSchemas(String target);
+import java.util.Map;
 
+public class JSONIntegerType extends JSONType {
+    public JSONIntegerType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("integer");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNullType.java
similarity index 68%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONNullType.java
index 03a234e..ec0adde 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNullType.java
@@ -14,19 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
+import org.apache.unomi.api.services.SchemaRegistry;
 
-import org.apache.unomi.api.SchemaType;
-
-import java.util.List;
-
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
-
-    List<SchemaType> getTargetSchemas(String target);
+import java.util.Map;
 
+public class JSONNullType extends JSONType {
+    public JSONNullType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("null");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNumberType.java
similarity index 67%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONNumberType.java
index 03a234e..bb6bf13 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNumberType.java
@@ -14,19 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
+import org.apache.unomi.api.services.SchemaRegistry;
 
-import org.apache.unomi.api.SchemaType;
-
-import java.util.List;
-
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
-
-    List<SchemaType> getTargetSchemas(String target);
+import java.util.Map;
 
+public class JSONNumberType extends JSONType {
+    public JSONNumberType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("number");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONObjectType.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONObjectType.java
new file mode 100644
index 0000000..45b25e0
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONObjectType.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.api.schema.json;
+
+import org.apache.unomi.api.services.SchemaRegistry;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class JSONObjectType extends JSONType {
+
+    Map<String,List<JSONType>> properties = new HashMap<>();
+    JSONType additionalProperties;
+    Map<String,List<JSONType>> patternProperties = new HashMap<>();
+    JSONType propertyNames;
+
+    int maxProperties;
+
+    public JSONObjectType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("object");
+        Map<String,Object> propertiesTree = (Map<String,Object>) schemaTree.get("properties");
+        if (propertiesTree != null) {
+            propertiesTree.entrySet().forEach(entry -> {
+                properties.put(entry.getKey(), jsonTypeFactory.getTypes((Map<String,Object>)entry.getValue()));
+            });
+        }
+    }
+
+    public Map<String,List<JSONType>> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(Map<String,List<JSONType>> properties) {
+        this.properties = properties;
+    }
+}
diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONSchema.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONSchema.java
new file mode 100644
index 0000000..544d009
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONSchema.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.unomi.api.schema.json;
+
+import org.apache.unomi.api.PluginType;
+import org.apache.unomi.api.services.SchemaRegistry;
+
+import java.util.List;
+import java.util.Map;
+
+public class JSONSchema extends JSONType implements PluginType {
+
+    private transient long pluginId;
+    private String schemaId;
+    private String target;
+    private List<JSONType> rootTypes;
+
+    private String vendor;
+    private String name;
+    private String version;
+
+    public JSONSchema(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        schemaId = (String) schemaTree.get("$id");
+        if (schemaTree.containsKey("self")) {
+            Map<String,Object> self = (Map<String,Object>) schemaTree.get("self");
+            name = (String) self.get("name");
+            vendor = (String) self.get("vendor");
+            version = (String) self.get("version");
+            target = (String) self.get("target");
+        }
+    }
+
+    public String getVendor() {
+        return vendor;
+    }
+
+    public void setVendor(String vendor) {
+        this.vendor = vendor;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public long getPluginId() {
+        return pluginId;
+    }
+
+    public void setPluginId(long pluginId) {
+        this.pluginId = pluginId;
+    }
+
+    public String getSchemaId() {
+        return schemaId;
+    }
+
+    public void setSchemaId(String schemaId) {
+        this.schemaId = schemaId;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
+    public List<JSONType> getRootTypes() {
+        if (rootTypes == null) {
+            buildRootTypes();
+        }
+        return rootTypes;
+    }
+
+    private void buildRootTypes() {
+        rootTypes = jsonTypeFactory.getTypes(schemaTree);
+    }
+}
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONStringType.java
similarity index 67%
copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONStringType.java
index 03a234e..c1b9c10 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONStringType.java
@@ -14,19 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.unomi.api.schema.json;
 
-package org.apache.unomi.api.services;
+import org.apache.unomi.api.services.SchemaRegistry;
 
-import org.apache.unomi.api.SchemaType;
-
-import java.util.List;
-
-public interface SchemaRegistry {
-
-    boolean isValid(Object object, String schemaId);
-
-    SchemaType getSchema(String schemaId);
-
-    List<SchemaType> getTargetSchemas(String target);
+import java.util.Map;
 
+public class JSONStringType extends JSONType {
+    public JSONStringType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        super(schemaTree, jsonTypeFactory, schemaRegistry);
+        setType("string");
+    }
 }
diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONType.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONType.java
new file mode 100644
index 0000000..3b60b0f
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONType.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.api.schema.json;
+
+import org.apache.unomi.api.services.SchemaRegistry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class JSONType {
+
+    String type;
+    String name;
+    List<String> required;
+    String ref;
+    List<JSONType> anyOf;
+    List<JSONType> oneOf;
+
+    Map<String,Object> customKeywords;
+
+    protected Map<String,Object> schemaTree;
+
+    protected JSONTypeFactory jsonTypeFactory;
+
+    protected SchemaRegistry schemaRegistry;
+
+    public JSONType(Map<String,Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) {
+        this.schemaTree = schemaTree;
+        this.jsonTypeFactory = jsonTypeFactory;
+        this.schemaRegistry = schemaRegistry;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Map<String, Object> getSchemaTree() {
+        return schemaTree;
+    }
+
+    public JSONTypeFactory getJsonTypeFactory() {
+        return jsonTypeFactory;
+    }
+
+    public SchemaRegistry getSchemaRegistry() {
+        return schemaRegistry;
+    }
+
+    public String getRef() {
+        ref = (String) schemaTree.get("$ref");
+        return ref;
+    }
+
+    public List<JSONType> getAllOf() {
+        List<Map<String,Object>> allOfTree = (List<Map<String,Object>>) schemaTree.get("allOf");
+        List<JSONType> allOfTypes = new ArrayList<>();
+        if (allOfTree != null) {
+            for (Map<String,Object> allOfEntry : allOfTree) {
+                List<JSONType> entryTypes = jsonTypeFactory.getTypes(allOfEntry);
+                allOfTypes.addAll(entryTypes);
+            }
+        }
+        return allOfTypes;
+    }
+
+    public List<JSONType> getAnyOf() {
+        return anyOf;
+    }
+
+    public List<JSONType> getOneOf() {
+        return oneOf;
+    }
+
+    public Map<String, Object> getCustomKeywords() {
+        return customKeywords;
+    }
+
+    public boolean merge(JSONType anotherType) {
+        if (!anotherType.getType().equals(getType())) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java
new file mode 100644
index 0000000..da79016
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.api.schema.json;
+
+import org.apache.unomi.api.services.SchemaRegistry;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class JSONTypeFactory {
+
+    Map<String, Class<? extends JSONType>> jsonTypes = new HashMap<>();
+
+    SchemaRegistry schemaRegistry;
+
+    public JSONTypeFactory(SchemaRegistry schemaRegistry) {
+        this.schemaRegistry = schemaRegistry;
+        jsonTypes.put("object", JSONObjectType.class);
+        jsonTypes.put("string", JSONStringType.class);
+        jsonTypes.put("array", JSONArrayType.class);
+        jsonTypes.put("number", JSONNumberType.class);
+        jsonTypes.put("integer", JSONIntegerType.class);
+        jsonTypes.put("boolean", JSONBooleanType.class);
+        jsonTypes.put("null", JSONNullType.class);
+    }
+
+    List<JSONType> getTypes(Map<String,Object> schemaTree) {
+        if (schemaTree.containsKey("$ref")) {
+            String schemaId = (String) schemaTree.get("$ref");
+            JSONSchema refSchema = schemaRegistry.getSchema(schemaId);
+            if (refSchema != null) {
+                schemaTree = refSchema.getSchemaTree();
+            } else {
+                System.err.println("Couldn't find schema for ref " + schemaId);
+            }
+        }
+        if (schemaTree.containsKey("enum")) {
+            List<JSONType> result = new ArrayList<>();
+            result.add(new JSONEnumType(schemaTree, this, schemaRegistry));
+            return result;
+        }
+        Object typeObject = schemaTree.get("type");
+        if (typeObject == null) {
+            return new ArrayList<>();
+        }
+        List<String> types = null;
+        if (typeObject instanceof String) {
+            types = new ArrayList<>();
+            types.add((String) typeObject);
+        } else {
+            types = (List<String>) typeObject;
+        }
+        List<JSONType> resultJsonTypes = new ArrayList<>();
+        for (String type : types) {
+            if (type == null) {
+                continue;
+            }
+            if (!jsonTypes.containsKey(type)) {
+                continue;
+            }
+            Class<? extends JSONType> typeClass = jsonTypes.get(type);
+            Constructor<? extends JSONType> constructor = null;
+            try {
+                constructor = typeClass.getConstructor(Map.class, JSONTypeFactory.class, SchemaRegistry.class);
+                resultJsonTypes.add(constructor.newInstance(schemaTree, this, schemaRegistry));
+            } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return resultJsonTypes;
+    }
+
+}
diff --git a/api/src/main/java/org/apache/unomi/api/services/EventService.java b/api/src/main/java/org/apache/unomi/api/services/EventService.java
index c6136a3..4dde0a9 100644
--- a/api/src/main/java/org/apache/unomi/api/services/EventService.java
+++ b/api/src/main/java/org/apache/unomi/api/services/EventService.java
@@ -19,7 +19,6 @@ package org.apache.unomi.api.services;
 
 import org.apache.unomi.api.Event;
 import org.apache.unomi.api.EventProperty;
-import org.apache.unomi.api.EventType;
 import org.apache.unomi.api.PartialList;
 import org.apache.unomi.api.Session;
 import org.apache.unomi.api.actions.ActionPostExecutor;
@@ -72,7 +71,7 @@ public interface EventService {
 
 
     /**
-     * Check if event fields complies with corresponding {@link EventType} definition
+     * Check if event fields complies with corresponding event JSON schema definition
      *
      * @param event        event to test
      * @return true if the event is valid
@@ -97,19 +96,6 @@ public interface EventService {
     List<EventProperty> getEventProperties();
 
     /**
-     * Retrieves an event type
-     * @param typeName the name identifier for the event type
-     * @return the EventType object corresponding to the name, or null if not found.
-     */
-    EventType getEventType(String typeName);
-
-    /**
-     * Registers event type
-     * @param eventType event type to register
-     */
-    void registerEventType(EventType eventType);
-
-    /**
      * Retrieves the set of known event type identifiers.
      *
      * @return the set of known event type identifiers.
diff --git a/api/src/main/java/org/apache/unomi/api/services/EventTypeRegistry.java b/api/src/main/java/org/apache/unomi/api/services/EventTypeRegistry.java
deleted file mode 100644
index c81668c..0000000
--- a/api/src/main/java/org/apache/unomi/api/services/EventTypeRegistry.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.unomi.api.services;
-
-import org.apache.unomi.api.Event;
-import org.apache.unomi.api.EventType;
-
-import java.util.Collection;
-
-/**
- * An event types registry service.
- */
-public interface EventTypeRegistry {
-
-    /**
-     * Retrieve event type definition
-     *
-     * @param typeName name of the event type
-     * @return {@link EventType} definition
-     */
-    EventType get(String typeName);
-
-    /**
-     * Adds event type definition to registry
-     *
-     * @param eventType {@link EventType} definition
-     */
-    void register(EventType eventType);
-
-    /**
-     * Checks if event complies with {@link EventType} definition
-     *
-     * @param event the event to validate
-     * @return result of validation
-     */
-    boolean isValid(Event event);
-
-    /**
-     * List all known event types
-     *
-     * @return Lists all known {@link EventType}s
-     */
-    Collection<EventType> getAll();
-}
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
index 03a234e..1bdea07 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
@@ -17,16 +17,21 @@
 
 package org.apache.unomi.api.services;
 
-import org.apache.unomi.api.SchemaType;
+import org.apache.unomi.api.schema.json.JSONSchema;
 
+import java.io.InputStream;
 import java.util.List;
 
 public interface SchemaRegistry {
 
     boolean isValid(Object object, String schemaId);
 
-    SchemaType getSchema(String schemaId);
+    JSONSchema getSchema(String schemaId);
 
-    List<SchemaType> getTargetSchemas(String target);
+    List<JSONSchema> getTargetSchemas(String target);
+
+    String registerSchema(String target, InputStream jsonSchemaInputStream);
+
+    boolean unregisterSchema(String target, String schemaId);
 
 }
diff --git a/api/src/main/java/org/apache/unomi/api/utils/ParserHelper.java b/api/src/main/java/org/apache/unomi/api/utils/ParserHelper.java
index 57adc7f..a79d2d6 100644
--- a/api/src/main/java/org/apache/unomi/api/utils/ParserHelper.java
+++ b/api/src/main/java/org/apache/unomi/api/utils/ParserHelper.java
@@ -213,7 +213,7 @@ public class ParserHelper {
                         eventTypeIds.add(eventTypeId);
                     }
                 }
-            } else if (condition.getConditionType().getParentCondition() != null) {
+            } else if (condition.getConditionType() != null && condition.getConditionType().getParentCondition() != null) {
                 visitConditions(condition.getConditionType().getParentCondition(), this);
             }
         }
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
index 1f2d9bb..5a02c80 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
@@ -33,10 +33,12 @@ import graphql.schema.GraphQLOutputType;
 import graphql.schema.GraphQLSchema;
 import graphql.schema.GraphQLType;
 import graphql.schema.visibility.GraphqlFieldVisibility;
-import org.apache.unomi.api.EventType;
 import org.apache.unomi.api.PropertyType;
-import org.apache.unomi.api.services.EventTypeRegistry;
+import org.apache.unomi.api.schema.json.JSONObjectType;
+import org.apache.unomi.api.schema.json.JSONSchema;
+import org.apache.unomi.api.schema.json.JSONType;
 import org.apache.unomi.api.services.ProfileService;
+import org.apache.unomi.api.services.SchemaRegistry;
 import org.apache.unomi.graphql.CDPGraphQLConstants;
 import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter;
 import org.apache.unomi.graphql.fetchers.CustomEventOrSetPropertyDataFetcher;
@@ -72,13 +74,7 @@ import org.apache.unomi.graphql.utils.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static graphql.schema.FieldCoordinates.coordinates;
@@ -92,7 +88,7 @@ public class GraphQLSchemaProvider {
 
     private final ProfileService profileService;
 
-    private final EventTypeRegistry eventTypeRegistry;
+    private final SchemaRegistry schemaRegistry;
 
     private final List<GraphQLTypeFunctionProvider> typeFunctionProviders;
 
@@ -116,9 +112,83 @@ public class GraphQLSchemaProvider {
 
     private Set<Class<?>> additionalTypes = new HashSet<>();
 
+    public interface DefinitionType {
+        String getTypeId();
+        String getName();
+        boolean hasSubTypes();
+        List<DefinitionType> getSubTypes();
+    }
+
+    public class PropertyTypeDefinitionType implements DefinitionType {
+
+        private PropertyType propertyType;
+
+        public PropertyTypeDefinitionType(PropertyType propertyType) {
+            this.propertyType = propertyType;
+        }
+
+        @Override
+        public String getTypeId() {
+            return propertyType.getValueTypeId();
+        }
+
+        @Override
+        public String getName() {
+            return propertyType.getItemId();
+        }
+
+        @Override
+        public boolean hasSubTypes() {
+            return "set".equals(propertyType.getValueTypeId());
+        }
+
+        @Override
+        public List<DefinitionType> getSubTypes() {
+            return propertyType.getChildPropertyTypes().stream().map(PropertyTypeDefinitionType::new).collect(Collectors.toList());
+        }
+    }
+
+    public class JSONTypeDefinitionType implements DefinitionType {
+        private List<JSONType> jsonTypes;
+        private JSONType firstNonNullType;
+        private String name;
+
+        public JSONTypeDefinitionType(String name, List<JSONType> jsonTypes) {
+            this.name = name;
+            this.jsonTypes = jsonTypes;
+            Optional<JSONType> firstNonNullType = jsonTypes.stream().filter(jsonType -> !"null".equals(jsonType.getType())).findFirst();
+            if (firstNonNullType.isPresent()) {
+                this.firstNonNullType = firstNonNullType.get();
+            }
+        }
+
+        @Override
+        public String getTypeId() {
+            return firstNonNullType.getType();
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public boolean hasSubTypes() {
+            return firstNonNullType instanceof JSONObjectType && ((JSONObjectType) firstNonNullType).getProperties() != null;
+        }
+
+        @Override
+        public List<DefinitionType> getSubTypes() {
+            if (!hasSubTypes()) {
+                return new ArrayList<>();
+            }
+            return ((JSONObjectType) firstNonNullType).getProperties().entrySet().stream().map(entry -> new JSONTypeDefinitionType(entry.getKey(), entry.getValue())).collect(Collectors.toList());
+        }
+    }
+
     private GraphQLSchemaProvider(final Builder builder) {
         this.profileService = builder.profileService;
-        this.eventTypeRegistry = builder.eventTypeRegistry;
+        this.schemaRegistry = builder.schemaRegistry;
         this.eventPublisher = builder.eventPublisher;
         this.typeFunctionProviders = builder.typeFunctionProviders;
         this.extensionsProviders = builder.extensionsProviders;
@@ -238,20 +308,21 @@ public class GraphQLSchemaProvider {
             }
         }
 
-        final Collection<PropertyType> propertyTypes = profileService.getTargetPropertyTypes("profiles");
+        final Collection<PropertyType> profilePropertyTypes = profileService.getTargetPropertyTypes("profiles");
+        final Collection<DefinitionType> profileDefinitionTypes = profilePropertyTypes.stream().map(PropertyTypeDefinitionType::new).collect(Collectors.toList());
 
         // Profile
-        registerDynamicInputFilterFields(CDPProfilePropertiesFilterInput.TYPE_NAME, CDPProfilePropertiesFilterInput.class, propertyTypes);
-        registerDynamicInputFilterFields(CDPProfileUpdateEventFilterInput.TYPE_NAME, CDPProfileUpdateEventFilterInput.class, propertyTypes);
-        registerDynamicInputFields(CDPProfileUpdateEventInput.TYPE_NAME, CDPProfileUpdateEventInput.class, propertyTypes);
+        registerDynamicInputFilterFields(CDPProfilePropertiesFilterInput.TYPE_NAME, CDPProfilePropertiesFilterInput.class, profileDefinitionTypes);
+        registerDynamicInputFilterFields(CDPProfileUpdateEventFilterInput.TYPE_NAME, CDPProfileUpdateEventFilterInput.class, profileDefinitionTypes);
+        registerDynamicInputFields(CDPProfileUpdateEventInput.TYPE_NAME, CDPProfileUpdateEventInput.class, profileDefinitionTypes);
         registerDynamicEventFilterInputFields();
 
         // Profile
-        registerDynamicOutputFields(CDPProfile.TYPE_NAME, CDPProfile.class, CustomerPropertyDataFetcher.class, propertyTypes);
+        registerDynamicOutputFields(CDPProfile.TYPE_NAME, CDPProfile.class, CustomerPropertyDataFetcher.class, profileDefinitionTypes);
 
         // Persona
-        registerDynamicInputFields(CDPPersonaInput.TYPE_NAME, CDPPersonaInput.class, propertyTypes);
-        registerDynamicOutputFields(CDPPersona.TYPE_NAME, CDPPersona.class, CustomerPropertyDataFetcher.class, propertyTypes);
+        registerDynamicInputFields(CDPPersonaInput.TYPE_NAME, CDPPersonaInput.class, profileDefinitionTypes);
+        registerDynamicOutputFields(CDPPersona.TYPE_NAME, CDPPersona.class, CustomerPropertyDataFetcher.class, profileDefinitionTypes);
 
         // Events
         registerDynamicUnomiInputEvents(schemaBuilder);
@@ -260,18 +331,18 @@ public class GraphQLSchemaProvider {
     }
 
     private void registerDynamicUnomiInputEvents(GraphQLSchema.Builder schemaBuilder) {
-        final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll();
+        final List<JSONSchema> unomiEventTypes = schemaRegistry.getTargetSchemas("events");
 
         if (!unomiEventTypes.isEmpty()) {
-            for (EventType unomiEventType : unomiEventTypes) {
-                final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getType()) + "Input";
+            for (JSONSchema unomiEventType : unomiEventTypes) {
+                final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getName()) + "Input";
 
                 final GraphQLInputObjectType objectType;
                 if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
-                    objectType = createDynamicEventInputType(unomiEventType);
+                    objectType = createDynamicEventInputType(new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()));
                 } else {
                     objectType = (GraphQLInputObjectType) getFromTypeRegistry(typeName);
-                    registerDynamicInputFields(typeName, objectType, unomiEventType.getPropertyTypes());
+                    registerDynamicInputFields(typeName, objectType, new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()).getSubTypes());
                 }
 
                 if (objectType != null) {
@@ -282,20 +353,20 @@ public class GraphQLSchemaProvider {
     }
 
     private void registerDynamicUnomiOutputEvents(GraphQLSchema.Builder schemaBuilder) {
-        final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll();
+        final List<JSONSchema> unomiEventTypes = schemaRegistry.getTargetSchemas("events");
 
         if (!unomiEventTypes.isEmpty()) {
             final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder();
 
-            for (EventType unomiEventType : unomiEventTypes) {
-                final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getType());
+            for (JSONSchema unomiEventType : unomiEventTypes) {
+                final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getName());
 
                 final GraphQLObjectType objectType;
                 if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
-                    objectType = createDynamicEventOutputType(unomiEventType, codeRegisterBuilder);
+                    objectType = createDynamicEventOutputType(new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()), codeRegisterBuilder);
                 } else {
                     objectType = (GraphQLObjectType) getFromTypeRegistry(typeName);
-                    registerDynamicOutputFields(typeName, objectType, CustomerPropertyDataFetcher.class, unomiEventType.getPropertyTypes());
+                    registerDynamicOutputFields(typeName, objectType, CustomerPropertyDataFetcher.class, new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()).getSubTypes());
                 }
 
                 if (objectType != null) {
@@ -307,7 +378,7 @@ public class GraphQLSchemaProvider {
 
     private void registerDynamicInputFilterFields(final String typeName,
                                                   final Class<?> annotatedClass,
-                                                  final Collection<PropertyType> propertyTypes) {
+                                                  final Collection<DefinitionType> propertyTypes) {
         final GraphQLInputObjectType originalObject = getInputObjectType(annotatedClass);
 
         final List<GraphQLInputObjectField> inputObjectFields =
@@ -322,7 +393,7 @@ public class GraphQLSchemaProvider {
     private void registerDynamicOutputFields(final String graphQLTypeName,
                                              final Class<?> annotatedClass,
                                              final Class<? extends DynamicFieldDataFetcher> fetcherClass,
-                                             final Collection<PropertyType> propertyTypes) {
+                                             final Collection<DefinitionType> propertyTypes) {
         final GraphQLObjectType objectType = graphQLAnnotations.object(annotatedClass);
         registerDynamicOutputFields(graphQLTypeName, objectType, fetcherClass, propertyTypes);
     }
@@ -330,15 +401,15 @@ public class GraphQLSchemaProvider {
     private void registerDynamicOutputFields(final String graphQLTypeName,
                                              final GraphQLObjectType graphQLObjectType,
                                              final Class<? extends DynamicFieldDataFetcher> fetcherClass,
-                                             final Collection<PropertyType> propertyTypes) {
+                                             final Collection<DefinitionType> propertyTypes) {
         final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder();
 
         final List<GraphQLFieldDefinition> fieldDefinitions = new ArrayList<>();
 
         propertyTypes.forEach(propertyType -> {
-            final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId());
+            final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getName());
 
-            if ("set".equals(propertyType.getValueTypeId())) {
+            if (propertyType.hasSubTypes()) {
                 final String typeName = StringUtils.capitalize(propertyName);
 
                 if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
@@ -355,12 +426,12 @@ public class GraphQLSchemaProvider {
                 }
             } else {
                 fieldDefinitions.add(GraphQLFieldDefinition.newFieldDefinition()
-                        .type((GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getValueTypeId()))
+                        .type((GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getTypeId()))
                         .name(propertyName).build());
             }
 
             try {
-                final DataFetcher dataFetcher = fetcherClass.getConstructor(String.class, String.class).newInstance(propertyName, propertyType.getValueTypeId());
+                final DataFetcher dataFetcher = fetcherClass.getConstructor(String.class, String.class).newInstance(propertyName, propertyType.getTypeId());
                 codeRegisterBuilder.dataFetcher(FieldCoordinates.coordinates(graphQLTypeName, propertyName), dataFetcher);
             } catch (Exception e) {
                 throw new RuntimeException(String.format("Error creating a data fetcher with class %s for field %s", fetcherClass.getName(), propertyName), e);
@@ -375,20 +446,20 @@ public class GraphQLSchemaProvider {
     }
 
     private GraphQLObjectType createDynamicSetOutputType(
-            final PropertyType propertyType, final GraphQLCodeRegistry.Builder codeRegisterBuilder, final String parentName) {
+            final DefinitionType propertyType, final GraphQLCodeRegistry.Builder codeRegisterBuilder, final String parentName) {
 
-        return createDynamicOutputType(parentName != null ? parentName : propertyType.getItemId(), propertyType.getChildPropertyTypes(), null, codeRegisterBuilder);
+        return createDynamicOutputType(parentName != null ? parentName : propertyType.getName(), propertyType.getSubTypes(), null, codeRegisterBuilder);
     }
 
     private GraphQLObjectType createDynamicEventOutputType(
-            final EventType eventType, final GraphQLCodeRegistry.Builder codeRegisterBuilder) {
+            final DefinitionType eventType, final GraphQLCodeRegistry.Builder codeRegisterBuilder) {
 
         final Set<Class> interfaces = new HashSet<>();
         interfaces.add(CDPEventInterface.class);
-        return createDynamicOutputType(UnomiToGraphQLConverter.convertEventType(eventType.getType()), eventType.getPropertyTypes(), interfaces, codeRegisterBuilder);
+        return createDynamicOutputType(UnomiToGraphQLConverter.convertEventType(eventType.getName()), eventType.getSubTypes(), interfaces, codeRegisterBuilder);
     }
 
-    private GraphQLObjectType createDynamicOutputType(final String name, final Set<PropertyType> propertyTypes, final Set<Class> interfaces, final GraphQLCodeRegistry.Builder codeRegisterBuilder) {
+    private GraphQLObjectType createDynamicOutputType(final String name, final List<DefinitionType> propertyTypes, final Set<Class> interfaces, final GraphQLCodeRegistry.Builder codeRegisterBuilder) {
         final String typeName = StringUtils.capitalize(PropertyNameTranslator.translateFromUnomiToGraphQL(name));
 
         final GraphQLObjectType.Builder dynamicTypeBuilder = GraphQLObjectType.newObject()
@@ -413,15 +484,16 @@ public class GraphQLSchemaProvider {
         }
 
         if (propertyTypes != null && !propertyTypes.isEmpty()) {
+            //
             propertyTypes.forEach(childPropertyType -> {
-                final boolean isSet = "set".equals(childPropertyType.getValueTypeId());
-                String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getItemId());
+                final boolean isSet = childPropertyType.hasSubTypes();
+                String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getName());
 
                 GraphQLOutputType objectType = null;
                 if (isSet) {
                     objectType = createDynamicSetOutputType(childPropertyType, codeRegisterBuilder, typeName + "_" + childPropertyName);
                 } else {
-                    objectType = (GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getValueTypeId());
+                    objectType = (GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getTypeId());
                 }
 
                 if (objectType != null) {
@@ -446,15 +518,15 @@ public class GraphQLSchemaProvider {
         return null;
     }
 
-    private GraphQLInputObjectType createDynamicEventInputType(final EventType eventType) {
-        return createDynamicInputType(UnomiToGraphQLConverter.convertEventType(eventType.getType()), eventType.getPropertyTypes(), true);
+    private GraphQLInputObjectType createDynamicEventInputType(final DefinitionType eventType) {
+        return createDynamicInputType(UnomiToGraphQLConverter.convertEventType(eventType.getName()), eventType.getSubTypes(), true);
     }
 
-    private GraphQLInputObjectType createDynamicSetInputType(final PropertyType propertyType, final String parentName) {
-        return createDynamicInputType(parentName != null ? parentName : propertyType.getItemId(), propertyType.getChildPropertyTypes(), false);
+    private GraphQLInputObjectType createDynamicSetInputType(final DefinitionType propertyType, final String parentName) {
+        return createDynamicInputType(parentName != null ? parentName : propertyType.getName(), propertyType.getSubTypes(), false);
     }
 
-    private GraphQLInputObjectType createDynamicInputType(final String name, final Set<PropertyType> propertyTypes, final boolean isEvent) {
+    private GraphQLInputObjectType createDynamicInputType(final String name, final List<DefinitionType> propertyTypes, final boolean isEvent) {
         final String typeName = StringUtils.capitalize(PropertyNameTranslator.translateFromUnomiToGraphQL(name)) + "Input";
 
         final GraphQLInputObjectType.Builder dynamicTypeBuilder = GraphQLInputObjectType.newInputObject()
@@ -470,14 +542,14 @@ public class GraphQLSchemaProvider {
 
         if (propertyTypes != null && !propertyTypes.isEmpty()) {
             propertyTypes.forEach(childPropertyType -> {
-                final boolean isSet = "set".equals(childPropertyType.getValueTypeId());
-                String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getItemId());
+                final boolean isSet = childPropertyType.hasSubTypes();
+                String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getName());
 
                 GraphQLInputType objectType;
                 if (isSet) {
                     objectType = createDynamicSetInputType(childPropertyType, typeName + "_" + childPropertyName);
                 } else {
-                    objectType = (GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getValueTypeId());
+                    objectType = (GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getTypeId());
                 }
 
                 if (objectType != null) {
@@ -501,20 +573,20 @@ public class GraphQLSchemaProvider {
 
     private void registerDynamicInputFields(final String graphQLTypeName,
                                             final Class<?> clazz,
-                                            final Collection<PropertyType> propertyTypes) {
+                                            final Collection<DefinitionType> propertyTypes) {
         final GraphQLInputObjectType inputObjectType = getInputObjectType(clazz);
         registerDynamicInputFields(graphQLTypeName, inputObjectType, propertyTypes);
     }
 
     private void registerDynamicInputFields(final String graphQLTypeName,
                                             final GraphQLInputObjectType graphQLInputObjectType,
-                                            final Collection<PropertyType> propertyTypes) {
+                                            final Collection<DefinitionType> propertyTypes) {
         final List<GraphQLInputObjectField> fieldDefinitions = new ArrayList<>();
 
         propertyTypes.forEach(propertyType -> {
-            final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId());
+            final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getName());
 
-            if ("set".equals(propertyType.getValueTypeId())) {
+            if (propertyType.hasSubTypes()) {
                 final String typeName = StringUtils.capitalize(propertyName) + "Input";
 
                 if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) {
@@ -533,7 +605,7 @@ public class GraphQLSchemaProvider {
                 }
             } else {
                 fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
-                        .type((GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getValueTypeId()))
+                        .type((GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getTypeId()))
                         .name(propertyName)
                         .build());
             }
@@ -578,9 +650,9 @@ public class GraphQLSchemaProvider {
         }
 
         // now add all unomi defined event types
-        final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll();
+        final List<JSONSchema> unomiEventTypes = schemaRegistry.getTargetSchemas("events");
         unomiEventTypes.forEach(eventType -> {
-            final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getType());
+            final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getName());
             final GraphQLInputType eventInputType = (GraphQLInputType) getFromTypeRegistry(typeName + "Input");
             if (eventInputType == null) {
                 logger.warn("Couldn't find event input type {}", typeName + "Input, will not add it as a field.");
@@ -740,15 +812,15 @@ public class GraphQLSchemaProvider {
                 .getGraphQLType(annotatedClass, graphQLAnnotations.getContainer(), false);
     }
 
-    public static Builder create(final ProfileService profileService, final EventTypeRegistry eventTypeRegistry) {
-        return new Builder(profileService, eventTypeRegistry);
+    public static Builder create(final ProfileService profileService, final SchemaRegistry schemaRegistry) {
+        return new Builder(profileService, schemaRegistry);
     }
 
     static class Builder {
 
         final ProfileService profileService;
 
-        final EventTypeRegistry eventTypeRegistry;
+        final SchemaRegistry schemaRegistry;
 
         List<GraphQLTypeFunctionProvider> typeFunctionProviders;
 
@@ -768,9 +840,9 @@ public class GraphQLSchemaProvider {
 
         UnomiEventPublisher eventPublisher;
 
-        private Builder(final ProfileService profileService, final EventTypeRegistry eventTypeRegistry) {
+        private Builder(final ProfileService profileService, final SchemaRegistry schemaRegistry) {
             this.profileService = profileService;
-            this.eventTypeRegistry = eventTypeRegistry;
+            this.schemaRegistry = schemaRegistry;
         }
 
         public Builder typeFunctionProviders(List<GraphQLTypeFunctionProvider> typeFunctionProviders) {
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
index af5d992..24fb973 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
@@ -20,8 +20,8 @@ import graphql.GraphQL;
 import graphql.execution.SubscriptionExecutionStrategy;
 import graphql.schema.GraphQLCodeRegistry;
 import graphql.schema.GraphQLSchema;
-import org.apache.unomi.api.services.EventTypeRegistry;
 import org.apache.unomi.api.services.ProfileService;
+import org.apache.unomi.api.services.SchemaRegistry;
 import org.apache.unomi.graphql.fetchers.event.UnomiEventPublisher;
 import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider;
 import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider;
@@ -83,7 +83,7 @@ public class GraphQLSchemaUpdater {
 
     private ProfileService profileService;
 
-    private EventTypeRegistry eventTypeRegistry;
+    private SchemaRegistry schemaRegistry;
 
     private CDPEventInterfaceRegister eventInterfaceRegister;
 
@@ -131,8 +131,8 @@ public class GraphQLSchemaUpdater {
     }
 
     @Reference
-    public void setEventTypeRegistry(EventTypeRegistry eventTypeRegistry) {
-        this.eventTypeRegistry = eventTypeRegistry;
+    public void setSchemaRegistry(SchemaRegistry schemaRegistry) {
+        this.schemaRegistry = schemaRegistry;
     }
 
     @Reference
@@ -330,7 +330,7 @@ public class GraphQLSchemaUpdater {
 
     @SuppressWarnings("unchecked")
     private GraphQLSchema createGraphQLSchema() {
-        final GraphQLSchemaProvider schemaProvider = GraphQLSchemaProvider.create(profileService, eventTypeRegistry)
+        final GraphQLSchemaProvider schemaProvider = GraphQLSchemaProvider.create(profileService, schemaRegistry)
                 .typeFunctionProviders(typeFunctionProviders)
                 .extensionsProviders(extensionsProviders)
                 .additionalTypesProviders(additionalTypesProviders)
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java
index 436193a..49e0741 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java
@@ -35,7 +35,7 @@ import java.util.List;
 
 public class PropertyFilterUtils {
 
-    public static List<GraphQLInputObjectField> buildInputPropertyFilters(final Collection<PropertyType> propertyTypes, final GraphQLAnnotations graphQLAnnotations) {
+    public static List<GraphQLInputObjectField> buildInputPropertyFilters(final Collection<GraphQLSchemaProvider.DefinitionType> propertyTypes, final GraphQLAnnotations graphQLAnnotations) {
         if (propertyTypes == null || propertyTypes.isEmpty()) {
             return Collections.emptyList();
         }
@@ -47,10 +47,10 @@ public class PropertyFilterUtils {
         return fieldDefinitions;
     }
 
-    private static void addFilters(final List<GraphQLInputObjectField> fieldDefinitions, final PropertyType propertyType, final GraphQLAnnotations graphQLAnnotations) {
-        final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId());
+    private static void addFilters(final List<GraphQLInputObjectField> fieldDefinitions, final GraphQLSchemaProvider.DefinitionType propertyType, final GraphQLAnnotations graphQLAnnotations) {
+        final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getName());
 
-        if ("integer".equals(propertyType.getValueTypeId())) {
+        if ("integer".equals(propertyType.getTypeId())) {
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
                     .type(Scalars.GraphQLInt)
@@ -71,7 +71,7 @@ public class PropertyFilterUtils {
                     .name(propertyName + "_gte")
                     .type(Scalars.GraphQLInt)
                     .build());
-        } else if ("long".equals(propertyType.getValueTypeId())) {
+        } else if ("long".equals(propertyType.getTypeId())) {
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
                     .type(Scalars.GraphQLLong)
@@ -92,7 +92,7 @@ public class PropertyFilterUtils {
                     .name(propertyName + "_gte")
                     .type(Scalars.GraphQLLong)
                     .build());
-        } else if ("float".equals(propertyType.getValueTypeId())) {
+        } else if ("float".equals(propertyType.getTypeId())) {
 
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
@@ -114,7 +114,7 @@ public class PropertyFilterUtils {
                     .name(propertyName + "_gte")
                     .type(Scalars.GraphQLFloat)
                     .build());
-        } else if ("date".equals(propertyType.getValueTypeId())) {
+        } else if ("date".equals(propertyType.getTypeId())) {
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
                     .type(DateTimeFunction.DATE_TIME_SCALAR)
@@ -135,18 +135,18 @@ public class PropertyFilterUtils {
                     .name(propertyName + "_gte")
                     .type(DateTimeFunction.DATE_TIME_SCALAR)
                     .build());
-        } else if ("boolean".equals(propertyType.getValueTypeId())) {
+        } else if ("boolean".equals(propertyType.getTypeId())) {
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
                     .type(Scalars.GraphQLBoolean)
                     .build());
-        } else if ("id".equals(propertyType.getValueTypeId())) {
+        } else if ("id".equals(propertyType.getTypeId())) {
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
                     .type(Scalars.GraphQLString)
                     .build());
-        } else if ("set".equals(propertyType.getValueTypeId())) {
-            if (propertyType.getChildPropertyTypes() != null && !propertyType.getChildPropertyTypes().isEmpty()) {
+        } else if ("set".equals(propertyType.getTypeId())) {
+            if (propertyType.hasSubTypes()) {
                 final String typeName = StringUtils.capitalize(propertyName) + "FilterInput";
 
                 GraphQLInputObjectType inputObjectType;
@@ -156,7 +156,7 @@ public class PropertyFilterUtils {
 
                     final List<GraphQLInputObjectField> setFieldDefinitions = new ArrayList<>();
 
-                    propertyType.getChildPropertyTypes().forEach(childPropertyType ->
+                    propertyType.getSubTypes().forEach(childPropertyType ->
                             addFilters(setFieldDefinitions, childPropertyType, graphQLAnnotations));
 
                     dynamicTypeBuilder.fields(setFieldDefinitions);
@@ -173,7 +173,7 @@ public class PropertyFilterUtils {
                         .type(inputObjectType)
                         .build());
             }
-        } else if ("geopoint".equals(propertyType.getValueTypeId())) {
+        } else if ("geopoint".equals(propertyType.getTypeId())) {
 
             fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField()
                     .name(propertyName + "_equals")
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java
index f766175..fc15ed4 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java
@@ -18,8 +18,8 @@ package org.apache.unomi.graphql.types.resolvers;
 
 import graphql.TypeResolutionEnvironment;
 import graphql.schema.GraphQLObjectType;
-import org.apache.unomi.api.EventType;
-import org.apache.unomi.api.services.EventTypeRegistry;
+import org.apache.unomi.api.schema.json.JSONSchema;
+import org.apache.unomi.api.services.SchemaRegistry;
 import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter;
 import org.apache.unomi.graphql.services.ServiceManager;
 import org.apache.unomi.graphql.types.output.CDPEventInterface;
@@ -29,12 +29,12 @@ public class CDPEventInterfaceResolver extends BaseTypeResolver {
     @Override
     public GraphQLObjectType getType(TypeResolutionEnvironment env) {
         final ServiceManager serviceManager = env.getContext();
-        final EventTypeRegistry eventTypeRegistry = serviceManager.getService(EventTypeRegistry.class);
+        SchemaRegistry schemaRegistry = serviceManager.getService(SchemaRegistry.class);
 
         final CDPEventInterface eventInterface = env.getObject();
-        final EventType eventType = eventTypeRegistry.get(eventInterface.getEvent().getEventType());
-        if (eventType != null) {
-            final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getType());
+        final JSONSchema eventSchema = schemaRegistry.getSchema("https://unomi.apache.org/schemas/json/events/" + eventInterface.getEvent().getEventType() + "/1-0-0");
+        if (eventSchema != null) {
+            final String typeName = UnomiToGraphQLConverter.convertEventType(eventSchema.getSchemaId());
             return env.getSchema().getObjectType(typeName);
         } else {
             return super.getType(env);
diff --git a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
index 17fca68..d39569b 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
@@ -24,6 +24,7 @@ import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.rules.Rule;
 import org.apache.unomi.api.services.DefinitionsService;
 import org.apache.unomi.api.services.RulesService;
+import org.apache.unomi.api.services.SchemaRegistry;
 import org.apache.unomi.lifecycle.BundleWatcher;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
@@ -99,6 +100,10 @@ public abstract class BaseIT {
     @Filter(timeout = 600000)
     protected ConfigurationAdmin configurationAdmin;
 
+    @Inject
+    @Filter(timeout = 600000)
+    protected SchemaRegistry schemaRegistry;
+
     @Before
     public void waitForStartup() throws InterruptedException {
         while (!bundleWatcher.isStartupComplete()) {
@@ -286,6 +291,7 @@ public abstract class BaseIT {
         persistenceService = getService(PersistenceService.class);
         definitionsService = getService(DefinitionsService.class);
         rulesService = getService(RulesService.class);
+        schemaRegistry = getService(SchemaRegistry.class);
     }
 
     public void updateConfiguration(String serviceName, String configPid, String propName, Object propValue) throws InterruptedException, IOException {
diff --git a/itests/src/test/java/org/apache/unomi/itests/BasicIT.java b/itests/src/test/java/org/apache/unomi/itests/BasicIT.java
index e726ce4..348bdc3 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BasicIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BasicIT.java
@@ -72,9 +72,9 @@ public class BasicIT extends BaseIT {
     private static final String TEST_SCOPE = "testScope";
 
     private static final String ITEM_TYPE_SITE = "site";
-    private static final String ITEM_ID_SITE = "/test/site";
+    private static final String ITEM_ID_SITE = "site-8f4d-4a07-8e96-d33ffa04d3d4";
     private static final String ITEM_TYPE_VISITOR = "VISITOR";
-    protected static final String ITEM_ID_PAGE_1 = "/test/site/page1";
+    protected static final String ITEM_ID_PAGE_1 = "page-8f4d-4a07-8e96-d33ffa04d3d4";
     protected static final String ITEM_TYPE_PAGE = "page";
 
     private static final String FIRST_NAME = "firstName";
diff --git a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
index 2df03c5..14a6c98 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
@@ -25,10 +25,7 @@ import org.apache.unomi.api.*;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.segments.Scoring;
 import org.apache.unomi.api.segments.Segment;
-import org.apache.unomi.api.services.DefinitionsService;
-import org.apache.unomi.api.services.EventService;
-import org.apache.unomi.api.services.ProfileService;
-import org.apache.unomi.api.services.SegmentService;
+import org.apache.unomi.api.services.*;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.junit.After;
@@ -39,10 +36,12 @@ import org.ops4j.pax.exam.junit.PaxExam;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
 import org.ops4j.pax.exam.spi.reactors.PerSuite;
 import org.ops4j.pax.exam.util.Filter;
+import org.osgi.framework.BundleContext;
 
 import javax.inject.Inject;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URI;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -62,7 +61,10 @@ import static org.junit.Assert.*;
 public class ContextServletIT extends BaseIT {
     private final static String CONTEXT_URL = "/cxs/context.json";
     private final static String THIRD_PARTY_HEADER_NAME = "X-Unomi-Peer";
-    private final static String SEGMENT_EVENT_TYPE = "test-event-type";
+    private final static String TEST_EVENT_TYPE = "test-event-type";
+    private final static String TEST_EVENT_TYPE_SCHEMA = "test-event-type.json";
+    private final static String FLOAT_PROPERTY_EVENT_TYPE = "float-property-type";
+    private final static String FLOAT_PROPERTY_EVENT_TYPE_SCHEMA = "float-property-type.json";
     private final static String SEGMENT_ID = "test-segment-id";
     private final static int SEGMENT_NUMBER_OF_DAYS = 30;
 
@@ -88,11 +90,16 @@ public class ContextServletIT extends BaseIT {
     @Filter(timeout = 600000)
     protected SegmentService segmentService;
 
+    @Inject
+    @Filter(timeout = 600000)
+    protected BundleContext bundleContext;
+
     private Profile profile;
 
     @Before
-    public void setUp() throws InterruptedException {
-        this.registerEventType(SEGMENT_EVENT_TYPE);
+    public void setUp() throws InterruptedException, IOException {
+        this.registerEventType(TEST_EVENT_TYPE_SCHEMA);
+        this.registerEventType(FLOAT_PROPERTY_EVENT_TYPE_SCHEMA);
 
         //Create a past-event segment
         Metadata segmentMetadata = new Metadata(SEGMENT_ID);
@@ -101,7 +108,7 @@ public class ContextServletIT extends BaseIT {
         segmentCondition.setParameter("minimumEventCount", 2);
         segmentCondition.setParameter("numberOfDays", SEGMENT_NUMBER_OF_DAYS);
         Condition pastEventEventCondition = new Condition(definitionsService.getConditionType("eventTypeCondition"));
-        pastEventEventCondition.setParameter("eventTypeId", SEGMENT_EVENT_TYPE);
+        pastEventEventCondition.setParameter("eventTypeId", TEST_EVENT_TYPE);
         segmentCondition.setParameter("eventCondition", pastEventEventCondition);
         segment.setCondition(segmentCondition);
         segmentService.setSegmentDefinition(segment);
@@ -120,38 +127,14 @@ public class ContextServletIT extends BaseIT {
         TestUtils.removeAllProfiles(definitionsService, persistenceService);
         profileService.delete(profile.getItemId(), false);
         segmentService.removeSegmentDefinition(SEGMENT_ID, false);
-    }
 
-    private void registerEventType(final String type) {
-        final Set<PropertyType> props = new HashSet<>();
-        registerEventType(type, props, null, null);
+        schemaRegistry.unregisterSchema("events", TEST_EVENT_TYPE);
+        schemaRegistry.unregisterSchema("events", FLOAT_PROPERTY_EVENT_TYPE);
     }
 
-    private void registerEventType(final String type, final Set<PropertyType> properties, final Set<PropertyType> source, final Set<PropertyType> target) {
-        final Set<PropertyType> typeProps = new HashSet<>();
-        if (properties != null) {
-            PropertyType propertiesPropType = new PropertyType();
-            propertiesPropType.setItemId("properties");
-            propertiesPropType.setValueTypeId("set");
-            propertiesPropType.setChildPropertyTypes(properties);
-            typeProps.add(propertiesPropType);
-        }
-        if (source != null) {
-            PropertyType sourcePropType = new PropertyType();
-            sourcePropType.setItemId("source");
-            sourcePropType.setValueTypeId("set");
-            sourcePropType.setChildPropertyTypes(source);
-            typeProps.add(sourcePropType);
-        }
-        if (target != null) {
-            PropertyType targetPropType = new PropertyType();
-            targetPropType.setItemId("target");
-            targetPropType.setValueTypeId("set");
-            targetPropType.setChildPropertyTypes(target);
-            typeProps.add(targetPropType);
-        }
-        final EventType eventType = new EventType(type, typeProps, 1);
-        eventService.registerEventType(eventType);
+    private void registerEventType(String jsonSchemaFileName) throws IOException {
+        InputStream jsonSchemaInputStream = bundleContext.getBundle().getResource("schemas/events/" + jsonSchemaFileName).openStream();
+        schemaRegistry.registerSchema("events", jsonSchemaInputStream);
     }
 
     @Test
@@ -162,7 +145,7 @@ public class ContextServletIT extends BaseIT {
         String sessionId = "test-session-id";
         String scope = "test-scope";
         String eventTypeOriginal = "test-event-type-original";
-        String eventTypeUpdated = "test-event-type-updated";
+        String eventTypeUpdated = TEST_EVENT_TYPE;
         Profile profile = new Profile(profileId);
         Session session = new Session(sessionId, profile, new Date(), scope);
         Event event = new Event(eventId, eventTypeOriginal, session, profile, scope, null, null, new Date());
@@ -172,8 +155,6 @@ public class ContextServletIT extends BaseIT {
         Thread.sleep(2000);
         event.setEventType(eventTypeUpdated); //change the event so we can see the update effect
 
-        this.registerEventType(eventTypeUpdated);
-
         //Act
         ContextRequest contextRequest = new ContextRequest();
         contextRequest.setSessionId(session.getItemId());
@@ -199,7 +180,7 @@ public class ContextServletIT extends BaseIT {
         String sessionId = "test-session-id";
         String scope = "test-scope";
         String eventTypeOriginal = "test-event-type-original";
-        String eventTypeUpdated = "test-event-type-updated";
+        String eventTypeUpdated = TEST_EVENT_TYPE;
         Profile profile = new Profile(profileId);
         Session session = new Session(sessionId, profile, new Date(), scope);
         Event event = new Event(eventId, eventTypeOriginal, session, profile, scope, null, null, new Date());
@@ -209,8 +190,6 @@ public class ContextServletIT extends BaseIT {
         Thread.sleep(2000);
         event.setEventType(eventTypeUpdated); //change the event so we can see the update effect
 
-        this.registerEventType(eventTypeUpdated);
-
         //Act
         ContextRequest contextRequest = new ContextRequest();
         contextRequest.setSessionId(session.getItemId());
@@ -235,7 +214,7 @@ public class ContextServletIT extends BaseIT {
         String sessionId = "test-session-id";
         String scope = "test-scope";
         String eventTypeOriginal = "test-event-type-original";
-        String eventTypeUpdated = "test-event-type-updated";
+        String eventTypeUpdated = TEST_EVENT_TYPE;
         Session session = new Session(sessionId, profile, new Date(), scope);
         Event event = new Event(eventId, eventTypeOriginal, session, profile, scope, null, null, new Date());
         this.eventService.send(event);
@@ -243,8 +222,6 @@ public class ContextServletIT extends BaseIT {
         Thread.sleep(2000);
         event.setEventType(eventTypeUpdated); //change the event so we can see the update effect
 
-        this.registerEventType(eventTypeUpdated);
-
         //Act
         ContextRequest contextRequest = new ContextRequest();
         contextRequest.setSessionId(session.getItemId());
@@ -267,7 +244,7 @@ public class ContextServletIT extends BaseIT {
         String sessionId = "test-session-id";
         String scope = "test-scope";
         Event event = new Event();
-        event.setEventType(SEGMENT_EVENT_TYPE);
+        event.setEventType(TEST_EVENT_TYPE);
         event.setScope(scope);
 
         //Act
@@ -298,7 +275,7 @@ public class ContextServletIT extends BaseIT {
         String sessionId = "test-session-id";
         String scope = "test-scope";
         Event event = new Event();
-        event.setEventType(SEGMENT_EVENT_TYPE);
+        event.setEventType(TEST_EVENT_TYPE);
         event.setScope(scope);
         String regularURI = URL + CONTEXT_URL;
         long oldTimestamp = LocalDateTime.now(ZoneId.of("UTC")).minusDays(SEGMENT_NUMBER_OF_DAYS + 1).toInstant(ZoneOffset.UTC).toEpochMilli();
@@ -330,7 +307,7 @@ public class ContextServletIT extends BaseIT {
         String sessionId = "test-session-id";
         String scope = "test-scope";
         Event event = new Event();
-        event.setEventType(SEGMENT_EVENT_TYPE);
+        event.setEventType(TEST_EVENT_TYPE);
         event.setScope(scope);
         String regularURI = URL + CONTEXT_URL;
         long futureTimestamp = LocalDateTime.now(ZoneId.of("UTC")).plusDays(1).toInstant(ZoneOffset.UTC).toEpochMilli();
@@ -371,8 +348,6 @@ public class ContextServletIT extends BaseIT {
         contextRequest.setProfileId(profileId);
         contextRequest.setEvents(Arrays.asList(event));
 
-        this.registerEventType(eventType);
-
         //Act
         HttpPost request = new HttpPost(URL + CONTEXT_URL);
         request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY);
@@ -391,7 +366,7 @@ public class ContextServletIT extends BaseIT {
         //Arrange
         String eventId = "valid-event-id-" + System.currentTimeMillis();
         String profileId = "valid-profile-id";
-        String eventType = "valid-event-type";
+        String eventType = FLOAT_PROPERTY_EVENT_TYPE;
         Event event = new Event();
         event.setEventType(eventType);
         event.setItemId(eventId);
@@ -403,13 +378,6 @@ public class ContextServletIT extends BaseIT {
         contextRequest.setProfileId(profileId);
         contextRequest.setEvents(Arrays.asList(event));
 
-        final Set<PropertyType> propertiesPropTypes = new HashSet<>();
-        PropertyType floatProp = new PropertyType();
-        floatProp.setItemId("floatProperty");
-        floatProp.setValueTypeId("float");
-        propertiesPropTypes.add(floatProp);
-        this.registerEventType(eventType, propertiesPropTypes, null, null);
-
         //Act
         HttpPost request = new HttpPost(URL + CONTEXT_URL);
         request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY);
@@ -429,7 +397,7 @@ public class ContextServletIT extends BaseIT {
         //Arrange
         String eventId = "invalid-event-value-id-" + System.currentTimeMillis();
         String profileId = "invalid-profile-id";
-        String eventType = "invalid-event-value-type";
+        String eventType = FLOAT_PROPERTY_EVENT_TYPE;
         Event event = new Event();
         event.setEventType(eventType);
         event.setItemId(eventId);
@@ -441,13 +409,6 @@ public class ContextServletIT extends BaseIT {
         contextRequest.setProfileId(profileId);
         contextRequest.setEvents(Arrays.asList(event));
 
-        final Set<PropertyType> propertiesPropTypes = new HashSet<>();
-        PropertyType floatProp = new PropertyType();
-        floatProp.setItemId("floatProperty");
-        floatProp.setValueTypeId("float");
-        propertiesPropTypes.add(floatProp);
-        this.registerEventType(eventType, propertiesPropTypes, null, null);
-
         //Act
         HttpPost request = new HttpPost(URL + CONTEXT_URL);
         request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY);
@@ -466,7 +427,7 @@ public class ContextServletIT extends BaseIT {
         //Arrange
         String eventId = "invalid-event-prop-id-" + System.currentTimeMillis();
         String profileId = "invalid-profile-id";
-        String eventType = "invalid-event-prop-type";
+        String eventType = FLOAT_PROPERTY_EVENT_TYPE;
         Event event = new Event();
         event.setEventType(eventType);
         event.setItemId(eventId);
@@ -478,17 +439,6 @@ public class ContextServletIT extends BaseIT {
         contextRequest.setProfileId(profileId);
         contextRequest.setEvents(Arrays.asList(event));
 
-        final Set<PropertyType> propertiesPropTypes = new HashSet<>();
-        PropertyType floatProp = new PropertyType();
-        floatProp.setItemId("floatProperty");
-        floatProp.setValueTypeId("float");
-        propertiesPropTypes.add(floatProp);
-        PropertyType geopointProp = new PropertyType();
-        geopointProp.setItemId("geopointProperty");
-        geopointProp.setValueTypeId("geopoint");
-        propertiesPropTypes.add(geopointProp);
-        this.registerEventType(eventType, propertiesPropTypes, null, null);
-
         //Act
         HttpPost request = new HttpPost(URL + CONTEXT_URL);
         request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY);
diff --git a/itests/src/test/resources/schemas/events/float-property-type.json b/itests/src/test/resources/schemas/events/float-property-type.json
new file mode 100644
index 0000000..ca09db1
--- /dev/null
+++ b/itests/src/test/resources/schemas/events/float-property-type.json
@@ -0,0 +1,22 @@
+{
+  "$id": "https://unomi.apache.org/schemas/json/events/float-property-type/1-0-0",
+  "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "name":"events/float-property-type",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
+  "title": "FloatPropertyEvent",
+  "type": "object",
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
+  "properties" : {
+    "properties" : {
+      "type" : "object",
+      "properties" : {
+        "floatProperty" : { "type" : "number" }
+      },
+      "additionalProperties": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/itests/src/test/resources/schemas/events/test-event-type.json b/itests/src/test/resources/schemas/events/test-event-type.json
new file mode 100644
index 0000000..46b56e2
--- /dev/null
+++ b/itests/src/test/resources/schemas/events/test-event-type.json
@@ -0,0 +1,13 @@
+{
+  "$id": "https://unomi.apache.org/schemas/json/events/test-event-type/1-0-0",
+  "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "name":"events/test-event-type",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
+  "title": "TestEvent",
+  "type": "object",
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }]
+}
\ No newline at end of file
diff --git a/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java
index 710ba11..f1bac4d 100644
--- a/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java
@@ -18,7 +18,6 @@ package org.apache.unomi.rest.endpoints;
 
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.Event;
-import org.apache.unomi.api.EventType;
 import org.apache.unomi.api.PartialList;
 import org.apache.unomi.api.query.Query;
 import org.apache.unomi.api.services.EventService;
@@ -91,15 +90,4 @@ public class EventServiceEndpoint {
         return eventService.getEventTypeIds();
     }
 
-    /**
-     * Returns the list of event properties
-     * @param typeName the type name identifier
-     * @return a List of EventProperty objects that make up the properties that the server has seen.
-     */
-    @GET
-    @Path("types/{typeName}")
-    public EventType getEventType(@PathParam("typeName") String typeName) {
-        return eventService.getEventType(typeName);
-    }
-
 }
diff --git a/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java b/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
index 7686797..be5ac44 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
@@ -22,7 +22,6 @@ import inet.ipaddr.IPAddressString;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.unomi.api.Event;
 import org.apache.unomi.api.EventProperty;
-import org.apache.unomi.api.EventType;
 import org.apache.unomi.api.Metadata;
 import org.apache.unomi.api.PartialList;
 import org.apache.unomi.api.PropertyType;
@@ -64,8 +63,6 @@ public class EventServiceImpl implements EventService {
 
     private BundleContext bundleContext;
 
-    private EventTypeRegistry eventTypeRegistry;
-
     private SchemaRegistry schemaRegistry;
 
     private Set<String> predefinedEventTypeIds = new LinkedHashSet<String>();
@@ -115,10 +112,6 @@ public class EventServiceImpl implements EventService {
         this.shouldBeCheckedEventSourceId = shouldBeCheckedEventSourceId;
     }
 
-    public void setEventTypeRegistry(EventTypeRegistry eventTypeRegistry) {
-        this.eventTypeRegistry = eventTypeRegistry;
-    }
-
     public void setSchemaRegistry(SchemaRegistry schemaRegistry) {
         this.schemaRegistry = schemaRegistry;
     }
@@ -147,8 +140,7 @@ public class EventServiceImpl implements EventService {
     }
 
     public boolean isEventValid(Event event) {
-        this.schemaRegistry.isValid(event, "https://unomi.apache.org/schemas/json/events/" + event.getEventType() + ".json");
-        return this.eventTypeRegistry.isValid(event);
+        return this.schemaRegistry.isValid(event, "https://unomi.apache.org/schemas/json/events/" + event.getEventType() + "/1-0-0");
     }
 
     public String authenticateThirdPartyServer(String key, String ip) {
@@ -228,15 +220,6 @@ public class EventServiceImpl implements EventService {
     }
 
     @Override
-    public EventType getEventType(String typeName) {
-        return eventTypeRegistry.get(typeName);
-    }
-
-    public void registerEventType(final EventType eventType) {
-        eventTypeRegistry.register(eventType);
-    }
-
-    @Override
     public List<EventProperty> getEventProperties() {
         Map<String, Map<String, Object>> mappings = persistenceService.getPropertiesMapping(Event.ITEM_TYPE);
         List<EventProperty> props = new ArrayList<>(mappings.size());
diff --git a/services/src/main/java/org/apache/unomi/services/impl/events/EventTypeRegistryImpl.java b/services/src/main/java/org/apache/unomi/services/impl/events/EventTypeRegistryImpl.java
deleted file mode 100644
index a6327a0..0000000
--- a/services/src/main/java/org/apache/unomi/services/impl/events/EventTypeRegistryImpl.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.unomi.services.impl.events;
-
-import org.apache.commons.beanutils.PropertyUtils;
-import org.apache.unomi.api.*;
-import org.apache.unomi.api.services.EventTypeRegistry;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.SynchronousBundleListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URL;
-import java.util.*;
-
-public class EventTypeRegistryImpl implements EventTypeRegistry, SynchronousBundleListener {
-
-    private static final Logger logger = LoggerFactory.getLogger(EventTypeRegistryImpl.class.getName());
-
-    private final Map<Long, List<EventType>> eventTypesByBundle = new HashMap<>();
-
-    private final Map<String, EventType> eventTypesById = new LinkedHashMap<>();
-
-    private BundleContext bundleContext;
-
-    public void bundleChanged(BundleEvent event) {
-        switch (event.getType()) {
-            case BundleEvent.STARTED:
-                processBundleStartup(event.getBundle().getBundleContext());
-                break;
-            case BundleEvent.STOPPING:
-                processBundleStop(event.getBundle().getBundleContext());
-                break;
-        }
-    }
-
-    public void init() {
-        processBundleStartup(bundleContext);
-
-        // process already started bundles
-        for (Bundle bundle : bundleContext.getBundles()) {
-            if (bundle.getBundleContext() != null && bundle.getBundleId() != bundleContext.getBundle().getBundleId()) {
-                processBundleStartup(bundle.getBundleContext());
-            }
-        }
-
-        bundleContext.addBundleListener(this);
-        logger.info("Event registry initialized.");
-    }
-
-    public void destroy() {
-        bundleContext.removeBundleListener(this);
-        logger.info("Event registry shutdown.");
-    }
-
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
-
-    public EventType get(String typeName) {
-        return eventTypesById.get(typeName);
-    }
-
-    public void register(EventType eventType) {
-        eventTypesById.put(eventType.getType(), eventType);
-    }
-
-    @Override
-    public boolean isValid(Event event) {
-        if (event == null) {
-            return false;
-        }
-        final EventType eventType = this.get(event.getEventType());
-        if (eventType == null) {
-            return false;
-        }
-
-        Set<PropertyType> propertiesPropertyTypes = findChildPropertyTypesById("properties", eventType.getPropertyTypes());
-        Set<PropertyType> sourcePropertyTypes = findChildPropertyTypesById("source", eventType.getPropertyTypes());
-        Set<PropertyType> targetPropertyTypes = findChildPropertyTypesById("target", eventType.getPropertyTypes());
-
-        return areObjectPropertiesValid(event.getProperties(), propertiesPropertyTypes) &&
-                areObjectPropertiesValid(event.getSource(), sourcePropertyTypes) &&
-                areObjectPropertiesValid(event.getTarget(), targetPropertyTypes);
-    }
-
-    /**
-     * Checks that all properties from map are defined in the property type set.
-     * Does not require all defined properties to be present in map.
-     *
-     * @param props map of properties to validate
-     * @param types set of a predefined event type properties
-     * @return boolean result of validation
-     */
-    private boolean areMapPropertiesValid(Map<Object, Object> props, Set<PropertyType> types) {
-        if (props == null || props.isEmpty() || types == null || types.isEmpty()) {
-            return true;
-        }
-        return props.entrySet().stream().allMatch(entry -> {
-            return types.stream().anyMatch(type -> {
-                if (!type.getItemId().equals(entry.getKey().toString())) {
-                    return false;
-                }
-                final Set<PropertyType> childTypes = type.getChildPropertyTypes();
-                if (childTypes.size() > 0 && entry.getValue() != null) {
-                    try {
-                        return areObjectPropertiesValid(entry.getValue(), childTypes);
-                    } catch (ClassCastException e) {
-                        logger.error("Event property '{}' value is invalid: {}", entry.getKey(), e.getCause());
-                        return false;
-                    }
-                } else {
-                    boolean valueTypeValid = testValueType(entry.getValue(), type.getValueTypeId());
-                    if (!valueTypeValid) {
-                        logger.warn("Event type validation error: value type for property {} is not valid", entry.getKey().toString());
-                    }
-                    return valueTypeValid;
-                }
-            });
-        });
-    }
-
-    private boolean areObjectPropertiesValid(Object object, Set<PropertyType> types) {
-        if (object == null) {
-            return true;
-        }
-        if (object instanceof Map) {
-            return areMapPropertiesValid((Map<Object,Object>) object, types);
-        }
-        PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(object);
-        return Arrays.stream(propertyDescriptors).allMatch(propertyDescriptor -> {
-            PropertyType propertyType = findPropertyTypeById(propertyDescriptor.getName(), types);
-            if (propertyType == null) {
-                logger.warn("Event type validation error: couldn't find property type for property {}", propertyDescriptor.getName());
-                return false;
-            }
-            if ("set".equals(propertyType.getValueTypeId())) {
-                boolean setPropertiesValid = false;
-                try {
-                    setPropertiesValid = areObjectPropertiesValid(PropertyUtils.getProperty(object, propertyDescriptor.getName()), propertyType.getChildPropertyTypes());
-                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
-                    logger.error("Error accessing property {} on object {}: {}", propertyDescriptor.getName(), object.toString(), e);
-                    return false;
-                }
-                if (!setPropertiesValid) {
-                    logger.warn("Event type validation error: set property for property {} are not valid", propertyDescriptor.getName());
-                    return false;
-                }
-            }
-            return true;
-        });
-    }
-
-    private Set<PropertyType> findChildPropertyTypesById(String id, Set<PropertyType> types) {
-        PropertyType propertyType = findPropertyTypeById(id, types);
-        if (propertyType == null) {
-            return new HashSet<>();
-        } else {
-            return propertyType.getChildPropertyTypes();
-        }
-    }
-
-    private PropertyType findPropertyTypeById(String id, Set<PropertyType> types) {
-        Optional<PropertyType> optionalPropertyType = types.stream().filter(propertyType -> propertyType.getItemId().equals(id)).findFirst();
-        return optionalPropertyType.orElse(null);
-
-    }
-
-    private boolean testValueType(final Object value, final String valueTypeId) {
-        switch (valueTypeId) {
-            case "integer":
-                return value instanceof Integer;
-            case "long":
-                return value instanceof Long;
-            case "float":
-                return value instanceof Double;
-            case "set":
-            case "json":
-                return value instanceof Map;
-            case "geopoint":
-                return value instanceof GeoPoint;
-            case "date":
-                return value instanceof Date;
-            case "boolean":
-                return value instanceof Boolean;
-            case "id":
-            case "string":
-                return value instanceof String;
-            default:
-                // return true if type is unknown cuz it may be custom
-                return true;
-        }
-    }
-
-    public Collection<EventType> getAll() {
-        return this.eventTypesById.values();
-    }
-
-    private void loadPredefinedEventTypes(BundleContext bundleContext) {
-        Enumeration<URL> predefinedEventTypes = bundleContext.getBundle().findEntries("META-INF/cxs/events", "*.json", true);
-        if (predefinedEventTypes == null) {
-            return;
-        }
-        List<EventType> bundleEventTypes = this.eventTypesByBundle.get(bundleContext.getBundle().getBundleId());
-
-        while (predefinedEventTypes.hasMoreElements()) {
-            URL predefinedEventTypeURL = predefinedEventTypes.nextElement();
-            logger.debug("Found predefined event type at " + predefinedEventTypeURL + ", loading... ");
-
-            try {
-                EventType eventType = CustomObjectMapper.getObjectMapper().readValue(predefinedEventTypeURL, EventType.class);
-                eventType.setPluginId(bundleContext.getBundle().getBundleId());
-                register(eventType);
-                bundleEventTypes.add(eventType);
-            } catch (Exception e) {
-                logger.error("Error while loading event type definition " + predefinedEventTypeURL, e);
-            }
-        }
-
-    }
-
-    private void processBundleStartup(BundleContext bundleContext) {
-        if (bundleContext == null) {
-            return;
-        }
-        eventTypesByBundle.put(bundleContext.getBundle().getBundleId(), new ArrayList<>());
-        loadPredefinedEventTypes(bundleContext);
-    }
-
-    private void processBundleStop(BundleContext bundleContext) {
-        if (bundleContext == null) {
-            return;
-        }
-        List<EventType> eventTypes = eventTypesByBundle.remove(bundleContext.getBundle().getBundleId());
-        if (eventTypes != null) {
-            for (EventType eventType : eventTypes) {
-                eventTypesById.remove(eventType.getType());
-            }
-        }
-    }
-}
diff --git a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java
index 3e93519..eb137e0 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java
@@ -17,12 +17,14 @@
 
 package org.apache.unomi.services.impl.schemas;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.networknt.schema.*;
 import com.networknt.schema.uri.URIFetcher;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.unomi.api.SchemaType;
+import org.apache.unomi.api.schema.json.JSONSchema;
+import org.apache.unomi.api.schema.json.JSONTypeFactory;
 import org.apache.unomi.api.services.ProfileService;
 import org.apache.unomi.api.services.SchemaRegistry;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
@@ -36,6 +38,8 @@ import org.slf4j.LoggerFactory;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleListener {
@@ -44,8 +48,8 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
 
     private static final Logger logger = LoggerFactory.getLogger(SchemaRegistryImpl.class.getName());
 
-    private final Map<Long, List<SchemaType>> schemaTypesByBundle = new HashMap<>();
-    private final Map<String, SchemaType> schemaTypesById = new HashMap<>();
+    private final Map<Long, List<JSONSchema>> schemaTypesByBundle = new HashMap<>();
+    private final Map<String, JSONSchema> schemaTypesById = new HashMap<>();
 
     private final Map<String, JsonSchema> jsonSchemasById = new LinkedHashMap<>();
 
@@ -55,8 +59,12 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
 
     private ProfileService profileService;
 
+    private JsonSchemaFactory jsonSchemaFactory;
+
     ObjectMapper objectMapper = new ObjectMapper();
 
+    Pattern uriPathPattern = Pattern.compile("/schemas/json(.*)/\\d-\\d-\\d");
+
     public void bundleChanged(BundleEvent event) {
         switch (event.getType()) {
             case BundleEvent.STARTED:
@@ -69,6 +77,16 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
     }
 
     public void init() {
+
+        JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909())
+                .addKeyword(new UnomiPropertyTypeKeyword(profileService, this))
+                .addKeyword(new NonValidationKeyword("self"))
+                .build();
+        jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909))
+                .addMetaSchema(jsonMetaSchema)
+                .defaultMetaSchemaURI(URI)
+                .uriFetcher(getBundleUriFetcher(bundleContext), "https", "http").build();
+
         processBundleStartup(bundleContext);
 
         // process already started bundles
@@ -112,12 +130,12 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
     }
 
     @Override
-    public List<SchemaType> getTargetSchemas(String target) {
-        return schemaTypesById.values().stream().filter(schemaType -> schemaType.getTarget().equals(target)).collect(Collectors.toList());
+    public List<JSONSchema> getTargetSchemas(String target) {
+        return schemaTypesById.values().stream().filter(jsonSchema -> jsonSchema.getTarget() != null && jsonSchema.getTarget().equals(target)).collect(Collectors.toList());
     }
 
     @Override
-    public SchemaType getSchema(String schemaId) {
+    public JSONSchema getSchema(String schemaId) {
         return schemaTypesById.get(schemaId);
     }
 
@@ -127,37 +145,23 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
             return;
         }
 
-        List<SchemaType> schemaTypes = this.schemaTypesByBundle.get(bundleContext.getBundle().getBundleId());
+        List<JSONSchema> jsonSchemas = this.schemaTypesByBundle.get(bundleContext.getBundle().getBundleId());
 
         while (predefinedSchemas.hasMoreElements()) {
             URL predefinedSchemaURL = predefinedSchemas.nextElement();
             logger.debug("Found predefined JSON schema at " + predefinedSchemaURL + ", loading... ");
 
-                JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909())
-                        .addKeyword(new PropertyTypeKeyword(profileService, this)).build();
-                JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909))
-                        .addMetaSchema(jsonMetaSchema)
-                        .defaultMetaSchemaURI(URI)
-                        .uriFetcher(getBundleUriFetcher(bundleContext), "https", "http").build();
             try (InputStream schemaInputStream = predefinedSchemaURL.openStream()) {
                 JsonSchema jsonSchema = jsonSchemaFactory.getSchema(schemaInputStream);
-                String schemaId = jsonSchema.getSchemaNode().get("$id").asText();
-                jsonSchemasById.put(schemaId, jsonSchema);
-                bundleIdBySchemaId.put(schemaId, bundleContext.getBundle().getBundleId());
-                SchemaType schemaType = new SchemaType();
-                schemaType.setPluginId(bundleContext.getBundle().getBundleId());
-                schemaType.setSchemaId(schemaId);
-                Map<String, Object> schemaTree = (Map<String, Object>) objectMapper.treeToValue(jsonSchema.getSchemaNode(), Map.class);
-                schemaType.setSchemaTree(schemaTree);
+                String schemaTarget = null;
                 String[] splitPath = predefinedSchemaURL.getPath().split("/");
                 if (splitPath.length > 5) {
                     String target = splitPath[4];
                     if (StringUtils.isNotBlank(target)) {
-                        schemaType.setTarget(target);
+                        schemaTarget = target;
                     }
                 }
-                schemaTypes.add(schemaType);
-                schemaTypesById.put(schemaId, schemaType);
+                registerSchema(bundleContext.getBundle().getBundleId(), jsonSchemas, schemaTarget, jsonSchema);
             } catch (Exception e) {
                 logger.error("Error while loading schema definition " + predefinedSchemaURL, e);
             }
@@ -165,6 +169,42 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
 
     }
 
+    public String registerSchema(String target, InputStream jsonSchemaInputStream) {
+        JsonSchema jsonSchema = jsonSchemaFactory.getSchema(jsonSchemaInputStream);
+        try {
+            return registerSchema(null, null, target, jsonSchema);
+        } catch (JsonProcessingException e) {
+            logger.error("Error registering JSON schema", e);
+            return null;
+        }
+    }
+
+    public boolean unregisterSchema(String target, String schemaId) {
+        jsonSchemasById.remove(schemaId);
+        schemaTypesById.remove(schemaId);
+        return true;
+    }
+
+    private String registerSchema(Long bundleId, List<JSONSchema> jsonSchemas, String target, JsonSchema jsonSchema) throws JsonProcessingException {
+        String schemaId = jsonSchema.getSchemaNode().get("$id").asText();
+        jsonSchemasById.put(schemaId, jsonSchema);
+        if (bundleContext != null) {
+            bundleIdBySchemaId.put(schemaId, bundleId);
+        }
+        Map<String, Object> schemaTree = (Map<String, Object>) objectMapper.treeToValue(jsonSchema.getSchemaNode(), Map.class);
+        JSONSchema unomiJsonSchema = new JSONSchema(schemaTree, new JSONTypeFactory(this), this);
+        if (bundleId != null) {
+            unomiJsonSchema.setPluginId(bundleId);
+        }
+        unomiJsonSchema.setSchemaId(schemaId);
+        unomiJsonSchema.setTarget(target);
+        if (jsonSchemas != null) {
+            jsonSchemas.add(unomiJsonSchema);
+        }
+        schemaTypesById.put(schemaId, unomiJsonSchema);
+        return schemaId;
+    }
+
     private URIFetcher getBundleUriFetcher(BundleContext bundleContext) {
         return uri -> {
             logger.debug("Fetching schema {}", uri);
@@ -173,7 +213,11 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
                 logger.error("Couldn't find bundle for schema {}", uri);
                 return null;
             }
-            String uriPath = uri.getPath().substring("/schemas/json".length());
+            Matcher uriPathMatcher = uriPathPattern.matcher(uri.getPath());
+            String uriPath = uri.getPath();
+            if (uriPathMatcher.matches()) {
+                uriPath = uriPathMatcher.group(1) + ".json";
+            }
             URL schemaURL = bundleContext.getBundle(bundleId).getResource("META-INF/cxs/schemas" + uriPath);
             if (schemaURL != null) {
                 return schemaURL.openStream();
@@ -196,12 +240,12 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList
         if (bundleContext == null) {
             return;
         }
-        List<SchemaType> schemaTypes = schemaTypesByBundle.remove(bundleContext.getBundle().getBundleId());
-        if (schemaTypes != null) {
-            for (SchemaType schemaType : schemaTypes) {
-                jsonSchemasById.remove(schemaType.getSchemaId());
-                bundleIdBySchemaId.remove(schemaType.getSchemaId());
-                schemaTypesById.remove(schemaType.getSchemaId());
+        List<JSONSchema> JSONSchemas = schemaTypesByBundle.remove(bundleContext.getBundle().getBundleId());
+        if (JSONSchemas != null) {
+            for (JSONSchema JSONSchema : JSONSchemas) {
+                jsonSchemasById.remove(JSONSchema.getSchemaId());
+                bundleIdBySchemaId.remove(JSONSchema.getSchemaId());
+                schemaTypesById.remove(JSONSchema.getSchemaId());
             }
         }
     }
diff --git a/services/src/main/java/org/apache/unomi/services/impl/schemas/PropertyTypeKeyword.java b/services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java
similarity index 95%
rename from services/src/main/java/org/apache/unomi/services/impl/schemas/PropertyTypeKeyword.java
rename to services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java
index 68afb41..4c5796d 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/schemas/PropertyTypeKeyword.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java
@@ -26,9 +26,9 @@ import org.slf4j.LoggerFactory;
 import java.text.MessageFormat;
 import java.util.*;
 
-class PropertyTypeKeyword extends AbstractKeyword {
+class UnomiPropertyTypeKeyword extends AbstractKeyword {
 
-    private static final Logger logger = LoggerFactory.getLogger(PropertyTypeKeyword.class);
+    private static final Logger logger = LoggerFactory.getLogger(UnomiPropertyTypeKeyword.class);
 
     private final ProfileService profileService;
     private final SchemaRegistryImpl schemaRegistry;
@@ -97,8 +97,8 @@ class PropertyTypeKeyword extends AbstractKeyword {
         }
     }
 
-    public PropertyTypeKeyword(ProfileService profileService, SchemaRegistryImpl schemaRegistry) {
-        super("propertyTypes");
+    public UnomiPropertyTypeKeyword(ProfileService profileService, SchemaRegistryImpl schemaRegistry) {
+        super("unomiPropertyTypes");
         this.profileService = profileService;
         this.schemaRegistry = schemaRegistry;
     }
diff --git a/services/src/main/resources/META-INF/cxs/schemas/condition.json b/services/src/main/resources/META-INF/cxs/schemas/condition.json
index 000ee1d..71dbe42 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/condition.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/condition.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/condition.json",
+  "$id": "https://unomi.apache.org/schemas/json/condition/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Condition",
   "type": "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json b/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json
index 85e78c8..22e1ad0 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/conditiontype.json",
+  "$id": "https://unomi.apache.org/schemas/json/conditiontype/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "ConditionType",
   "type": "object",
@@ -11,11 +11,11 @@
       "type" : "string"
     },
     "parentCondition" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/condition.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/condition/1-0-0"
     },
     "parameters" : {
       "type" : "object",
-      "additionalProperties": { "$ref" : "https://unomi.apache.org/schemas/json/parameter.json" },
+      "additionalProperties": { "$ref" : "https://unomi.apache.org/schemas/json/parameter/1-0-0" },
       "maxProperties": 50
     }
   }
diff --git a/services/src/main/resources/META-INF/cxs/schemas/consent.json b/services/src/main/resources/META-INF/cxs/schemas/consent.json
index c1eb229..bb357fe 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/consent.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/consent.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/consent.json",
+  "$id": "https://unomi.apache.org/schemas/json/consent/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Consent",
   "type": "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/consentType.json b/services/src/main/resources/META-INF/cxs/schemas/consentType.json
index 19f4bef..034a531 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/consentType.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/consentType.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/consentType.json",
+  "$id": "https://unomi.apache.org/schemas/json/consentType/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "ConsentType",
   "type": "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/customitem.json b/services/src/main/resources/META-INF/cxs/schemas/customitem.json
index 0c59480..3ae685a 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/customitem.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/customitem.json
@@ -1,11 +1,11 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/customitem.json",
+  "$id": "https://unomi.apache.org/schemas/json/customitem/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "CustomItem",
   "type": "object",
   "allOf": [
     {
-      "$ref": "https://unomi.apache.org/schemas/json/item.json"
+      "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0"
     }
   ],
   "properties": {
diff --git a/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json b/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json
index f05ccb6..fb2874f 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json
@@ -1,11 +1,18 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/customitems/page.json",
+  "$id": "https://unomi.apache.org/schemas/json/customitems/page/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "target" : "customitems",
+    "name":"page",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
   "title": "PageCustomItem",
   "type": "object",
   "allOf": [
     {
-      "$ref": "https://unomi.apache.org/schemas/json/customitem.json"
+      "$ref": "https://unomi.apache.org/schemas/json/customitem/1-0-0"
     }
   ],
   "properties": {
@@ -59,7 +66,7 @@
     "consentTypes": {
       "type" : ["null", "array"],
       "items" : {
-        "$href" : "https://unomi.apache.org/schemas/json/consentType.json"
+        "$href" : "https://unomi.apache.org/schemas/json/consentType/1-0-0"
       }
     }
   }
diff --git a/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json b/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json
index b6de454..2d67e75 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json
@@ -1,11 +1,18 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/customitems/site.json",
+  "$id": "https://unomi.apache.org/schemas/json/customitems/site/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "target" : "customitems",
+    "name": "site",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
   "title": "SiteCustomItem",
   "type": "object",
   "allOf": [
     {
-      "$ref": "https://unomi.apache.org/schemas/json/customitem.json"
+      "$ref": "https://unomi.apache.org/schemas/json/customitem/1-0-0"
     }
   ],
   "properties": {
diff --git a/services/src/main/resources/META-INF/cxs/schemas/event.json b/services/src/main/resources/META-INF/cxs/schemas/event.json
index 1b4a03e..66cb8ad 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/event.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/event.json
@@ -1,9 +1,9 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/event.json",
+  "$id": "https://unomi.apache.org/schemas/json/event/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Event",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/timestampeditem.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/timestampeditem/1-0-0" }],
   "properties" : {
     "eventType" : {
       "type" : "string",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/events/view.json b/services/src/main/resources/META-INF/cxs/schemas/events/form.json
similarity index 57%
copy from services/src/main/resources/META-INF/cxs/schemas/events/view.json
copy to services/src/main/resources/META-INF/cxs/schemas/events/form.json
index 5ea14a9..e4c1575 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/events/view.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/events/form.json
@@ -1,20 +1,27 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/events/view.json",
+  "$id": "https://unomi.apache.org/schemas/json/events/form/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
-  "title": "ViewEvent",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "target" : "events",
+    "name": "form",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
+  "title": "FormEvent",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
   "properties" : {
     "properties" : {
       "type" : "object",
-      "propertyTypes" : [ "events" ],
+      "unomiFormMappingLookup" : true,
       "maxProperties": 50
     },
     "source" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/customitems/site.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/customitems/site/1-0-0"
     },
     "target" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/customitems/page.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/customitems/page/1-0-0"
     }
   }
 }
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/cxs/schemas/events/view.json b/services/src/main/resources/META-INF/cxs/schemas/events/login.json
similarity index 52%
copy from services/src/main/resources/META-INF/cxs/schemas/events/view.json
copy to services/src/main/resources/META-INF/cxs/schemas/events/login.json
index 5ea14a9..f00ef58 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/events/view.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/events/login.json
@@ -1,20 +1,24 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/events/view.json",
+  "$id": "https://unomi.apache.org/schemas/json/events/login/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
-  "title": "ViewEvent",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "target" : "events",
+    "name": "login",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
+  "title": "LoginEvent",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
   "properties" : {
     "properties" : {
       "type" : "object",
-      "propertyTypes" : [ "events" ],
+      "unomiPropertyTypes" : [ "events" ],
       "maxProperties": 50
     },
-    "source" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/customitems/site.json"
-    },
     "target" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/customitems/page.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/customitem/1-0-0"
     }
   }
 }
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json b/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json
index e203d47..1f748e0 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json
@@ -1,20 +1,30 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/events/modifyConsent.json",
+  "$id": "https://unomi.apache.org/schemas/json/events/modifyConsent/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "target" : "events",
+    "name": "modifyConsent",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
   "title": "ModifyConsentEvent",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
   "properties" : {
     "properties" : {
-      "consent" : {
-        "$ref" : "https://unomi.apache.org/schemas/json/consent.json"
+      "type" : "object",
+      "properties" : {
+        "consent" : {
+          "$ref" : "https://unomi.apache.org/schemas/json/consent/1-0-0"
+        }
       }
     },
     "source" : {
-        "$ref" : "https://unomi.apache.org/schemas/json/customitems/page.json"
+        "$ref" : "https://unomi.apache.org/schemas/json/customitems/page/1-0-0"
     },
     "target" : {
-        "$ref" : "https://unomi.apache.org/schemas/json/customitem.json"
+        "$ref" : "https://unomi.apache.org/schemas/json/customitem/1-0-0"
     }
   }
 }
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/cxs/schemas/events/view.json b/services/src/main/resources/META-INF/cxs/schemas/events/view.json
index 5ea14a9..a85188a 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/events/view.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/events/view.json
@@ -1,20 +1,27 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/events/view.json",
+  "$id": "https://unomi.apache.org/schemas/json/events/view/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
+  "self":{
+    "vendor":"org.apache.unomi",
+    "target" : "events",
+    "name": "view",
+    "format":"jsonschema",
+    "version":"1-0-0"
+  },
   "title": "ViewEvent",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
   "properties" : {
     "properties" : {
       "type" : "object",
-      "propertyTypes" : [ "events" ],
+      "unomiPropertyTypes" : [ "events" ],
       "maxProperties": 50
     },
     "source" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/customitems/site.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/customitems/site/1-0-0"
     },
     "target" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/customitems/page.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/customitems/page/1-0-0"
     }
   }
 }
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/cxs/schemas/goal.json b/services/src/main/resources/META-INF/cxs/schemas/goal.json
index ee7c715..57d922b 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/goal.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/goal.json
@@ -1,15 +1,15 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/goal.json",
+  "$id": "https://unomi.apache.org/schemas/json/goal/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Goal",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/metadataitem.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/metadataitem/1-0-0" }],
   "properties" : {
     "startEvent" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/condition.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/condition/1-0-0"
     },
     "targetEvent" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/condition.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/condition/1-0-0"
     },
     "campaignId" : {
       "type" : "string"
diff --git a/services/src/main/resources/META-INF/cxs/schemas/item.json b/services/src/main/resources/META-INF/cxs/schemas/item.json
index b4d9f8a..ed9dff5 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/item.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/item.json
@@ -1,11 +1,11 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/item.json",
+  "$id": "https://unomi.apache.org/schemas/json/item/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Item",
   "type": "object",
   "properties" : {
     "itemId" : {
-      "type" : "string",
+      "type" : ["null","string"],
       "pattern" : "^(\\w|[-_@\\.]){0,60}$",
       "description" : "The identifier for the item"
     },
diff --git a/services/src/main/resources/META-INF/cxs/schemas/metadata.json b/services/src/main/resources/META-INF/cxs/schemas/metadata.json
index 2116bba..03d4f71 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/metadata.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/metadata.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/metadata.json",
+  "$id": "https://unomi.apache.org/schemas/json/metadata/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Metadata",
   "type": "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json b/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json
index 325dafe..fcdbe1c 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json
@@ -1,14 +1,14 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/metadataitem.json",
+  "$id": "https://unomi.apache.org/schemas/json/metadataitem/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "MetadataItem",
   "type": "object",
   "allOf": [
-    { "$ref": "https://unomi.apache.org/schemas/json/item.json" }
+    { "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" }
   ],
   "properties" : {
     "metadata" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/metadata.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/metadata/1-0-0"
     }
   }
 }
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/cxs/schemas/parameter.json b/services/src/main/resources/META-INF/cxs/schemas/parameter.json
index abea6ae..cba8c6d 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/parameter.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/parameter.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/parameter.json",
+  "$id": "https://unomi.apache.org/schemas/json/parameter/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Parameter",
   "type": "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/profile.json b/services/src/main/resources/META-INF/cxs/schemas/profile.json
index 2381b81..3bf8c81 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/profile.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/profile.json
@@ -1,11 +1,11 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/profile.json",
+  "$id": "https://unomi.apache.org/schemas/json/profile/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Profile",
   "type": "object",
   "allOf": [
     {
-      "$ref": "https://unomi.apache.org/schemas/json/item.json"
+      "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0"
     }
   ],
   "properties": {
diff --git a/services/src/main/resources/META-INF/cxs/schemas/session.json b/services/src/main/resources/META-INF/cxs/schemas/session.json
index b2534b4..61d6fed 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/session.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/session.json
@@ -1,11 +1,11 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/session.json",
+  "$id": "https://unomi.apache.org/schemas/json/session/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Session",
   "type": "object",
   "allOf": [
     {
-      "$ref": "https://unomi.apache.org/schemas/json/timestampeditem.json"
+      "$ref": "https://unomi.apache.org/schemas/json/timestampeditem/1-0-0"
     }
   ],
   "properties": {
@@ -13,7 +13,7 @@
       "type" : "string"
     },
     "profile" : {
-      "$ref" : "https://unomi.apache.org/schemas/json/profile.json"
+      "$ref" : "https://unomi.apache.org/schemas/json/profile/1-0-0"
     },
     "properties" : {
       "type" : "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json b/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json
index bee6c8f..1d7c6ad 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json
@@ -1,9 +1,9 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/timestampeditem.json",
+  "$id": "https://unomi.apache.org/schemas/json/timestampeditem/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "TimestampedItem",
   "type": "object",
-  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/item.json" }],
+  "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" }],
   "properties" : {
     "timeStamp" : {
       "type" : ["null","string"],
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json b/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json
index 8a3ed95..752057b 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/values/boolean.json",
+  "$id": "https://unomi.apache.org/schemas/json/values/boolean/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Boolean",
   "type": "boolean"
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/date.json b/services/src/main/resources/META-INF/cxs/schemas/values/date.json
index 7a39489..2ad0739 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/date.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/date.json
@@ -1,5 +1,5 @@
 {
-    "$id": "https://unomi.apache.org/schemas/json/values/date.json",
+    "$id": "https://unomi.apache.org/schemas/json/values/date/1-0-0",
     "$schema": "https://json-schema.org/draft/2019-09/schema",
     "title": "Date",
     "type": "string",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/email.json b/services/src/main/resources/META-INF/cxs/schemas/values/email.json
index 705f2f6..d425eff 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/email.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/email.json
@@ -1,5 +1,5 @@
 {
-    "$id": "https://unomi.apache.org/schemas/json/values/email.json",
+    "$id": "https://unomi.apache.org/schemas/json/values/email/1-0-0",
     "$schema": "https://json-schema.org/draft/2019-09/schema",
     "title": "Email",
     "type": "string",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/integer.json b/services/src/main/resources/META-INF/cxs/schemas/values/integer.json
index f5cb7b9..b3c68a6 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/integer.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/integer.json
@@ -1,5 +1,5 @@
 {
-    "$id": "https://unomi.apache.org/schemas/json/values/integer.json",
+    "$id": "https://unomi.apache.org/schemas/json/values/integer/1-0-0",
     "$schema": "https://json-schema.org/draft/2019-09/schema",
     "title": "Integer",
     "type": "integer"
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/long.json b/services/src/main/resources/META-INF/cxs/schemas/values/long.json
index 769c78a..9eb7c8d 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/long.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/long.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://unomi.apache.org/schemas/json/values/long.json",
+  "$id": "https://unomi.apache.org/schemas/json/values/long/1-0-0",
   "$schema": "https://json-schema.org/draft/2019-09/schema",
   "title": "Long",
   "type": "integer"
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/set.json b/services/src/main/resources/META-INF/cxs/schemas/values/set.json
index 34b8611..9f43666 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/set.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/set.json
@@ -1,5 +1,5 @@
 {
-    "$id": "https://unomi.apache.org/schemas/json/values/set.json",
+    "$id": "https://unomi.apache.org/schemas/json/values/set/1-0-0",
     "$schema": "https://json-schema.org/draft/2019-09/schema",
     "title": "Set",
     "type": "object",
diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/string.json b/services/src/main/resources/META-INF/cxs/schemas/values/string.json
index 6d5e0e8..f0b9c30 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/values/string.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/values/string.json
@@ -1,5 +1,5 @@
 {
-    "$id": "https://unomi.apache.org/schemas/json/values/string.json",
+    "$id": "https://unomi.apache.org/schemas/json/values/string/1-0-0",
     "$schema": "https://json-schema.org/draft/2019-09/schema",
     "title": "String",
     "type": "string"
diff --git a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 932b7d1..a8fa903 100644
--- a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -101,12 +101,6 @@
         </interfaces>
     </service>
 
-    <bean id="eventTypeRegistryImpl" class="org.apache.unomi.services.impl.events.EventTypeRegistryImpl" init-method="init"
-          destroy-method="destroy">
-        <property name="bundleContext" ref="blueprintBundleContext"/>
-    </bean>
-    <service id="eventTypeRegistry" ref="eventTypeRegistryImpl" interface="org.apache.unomi.api.services.EventTypeRegistry"/>
-
     <bean id="schemaRegistryImpl" class="org.apache.unomi.services.impl.schemas.SchemaRegistryImpl" init-method="init"
           destroy-method="destroy">
         <property name="bundleContext" ref="blueprintBundleContext"/>
@@ -119,7 +113,6 @@
         <property name="definitionsService" ref="definitionsServiceImpl"/>
         <property name="sourceService" ref="sourceServiceImpl"/>
         <property name="bundleContext" ref="blueprintBundleContext"/>
-        <property name="eventTypeRegistry" ref="eventTypeRegistryImpl"/>
         <property name="schemaRegistry" ref="schemaRegistryImpl" />
         <property name="predefinedEventTypeIds">
             <set>