diff --git a/graphql-jpa-query-annotations/src/main/java/com/introproventures/graphql/jpa/query/annotation/GraphQLReadEntityForRole.java b/graphql-jpa-query-annotations/src/main/java/com/introproventures/graphql/jpa/query/annotation/GraphQLReadEntityForRole.java
new file mode 100644
index 000000000..f3e577502
--- /dev/null
+++ b/graphql-jpa-query-annotations/src/main/java/com/introproventures/graphql/jpa/query/annotation/GraphQLReadEntityForRole.java
@@ -0,0 +1,13 @@
+package com.introproventures.graphql.jpa.query.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GraphQLReadEntityForRole {
+    String[] value();
+}
diff --git a/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Author.java b/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Author.java
index 406c81b6e..e4b91886c 100644
--- a/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Author.java
+++ b/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Author.java
@@ -31,6 +31,7 @@
 import javax.persistence.OneToMany;
 import javax.persistence.OrderBy;
 
+import com.introproventures.graphql.jpa.query.annotation.GraphQLReadEntityForRole;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
@@ -41,6 +42,7 @@
 @Setter
 @ToString
 @EqualsAndHashCode(exclude={"books","phoneNumbers"}) // Fixes NPE in Hibernate when initializing loaded collections #1
+@GraphQLReadEntityForRole({"admin"})
 public class Author {
 	@Id
 	Long id;
diff --git a/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java b/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java
index ce8045270..2fe40307d 100644
--- a/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java
+++ b/graphql-jpa-query-example-model-books/src/main/java/com/introproventures/graphql/jpa/query/schema/model/book/Book.java
@@ -29,10 +29,7 @@
 import javax.persistence.ManyToOne;
 import javax.persistence.Transient;
 
-import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription;
-import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore;
-import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnoreFilter;
-import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnoreOrder;
+import com.introproventures.graphql.jpa.query.annotation.*;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -40,6 +37,7 @@
 @Data
 @Entity
 @EqualsAndHashCode(exclude= {"author", "tags"})
+@GraphQLReadEntityForRole({"user", "admin"})
 public class Book {
 	@Id
 	Long id;
diff --git a/graphql-jpa-query-schema-mutations/pom.xml b/graphql-jpa-query-schema-mutations/pom.xml
new file mode 100644
index 000000000..2cfdb74f0
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.introproventures</groupId>
+        <artifactId>graphql-jpa-query-build</artifactId>
+        <version>0.3.36-SNAPSHOT</version>
+        <relativePath>../graphql-jpa-query-build</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>graphql-jpa-query-schema-mutations</artifactId>
+    <name>graphql-jpa-query-schema-mutations</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.introproventures</groupId>
+            <artifactId>graphql-jpa-query-annotations</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.introproventures</groupId>
+            <artifactId>graphql-jpa-query-schema</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.persistence</groupId>
+            <artifactId>javax.persistence-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.transaction</groupId>
+            <artifactId>javax.transaction-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.interceptor</groupId>
+            <artifactId>javax.interceptor-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>2.9.8</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.json/json -->
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20180813</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.8.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/GraphQLJpaSchemaBuilderWithMutation.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/GraphQLJpaSchemaBuilderWithMutation.java
new file mode 100644
index 000000000..058e45d98
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/GraphQLJpaSchemaBuilderWithMutation.java
@@ -0,0 +1,206 @@
+package com.introproventures.graphql.jpa.query.mutations;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import com.introproventures.graphql.jpa.query.mutations.fetcher.impl.*;
+
+import javax.persistence.EntityManager;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EmbeddableType;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.PluralAttribute;
+import javax.persistence.metamodel.SingularAttribute;
+import javax.persistence.metamodel.Type;
+
+import com.introproventures.graphql.jpa.query.schema.impl.FetcherParams;
+import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
+
+import graphql.schema.*;
+
+
+public class GraphQLJpaSchemaBuilderWithMutation extends GraphQLJpaSchemaBuilder {
+	public class GqlMutationOper {
+		private String operation;
+		private String description;
+		private Class<? extends GraphQLJpaEntityInputFetcher> fetcher;
+		
+		public GqlMutationOper(String oper, String description, Class<? extends GraphQLJpaEntityInputFetcher> fetcher) {
+			this.operation = oper;
+			this.description = description;
+			this.fetcher = fetcher;
+		}
+
+		public String getOperation() {
+			return operation;
+		}
+
+		public void setOperation(String operation) {
+			this.operation = operation;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public Class<? extends GraphQLJpaEntityInputFetcher> getFetcher() {
+			return fetcher;
+		}
+
+		public void setFetcher(Class<? extends GraphQLJpaEntityInputFetcher> fetcher) {
+			this.fetcher = fetcher;
+		}		
+	}
+
+	protected String suffixInputObjectType = "Input";
+	private List<GqlMutationOper> operations = new ArrayList<>(); 
+	private Map<EntityType<?>, GraphQLInputObjectType> entityInputCache = new HashMap<>();
+
+	public GraphQLJpaSchemaBuilderWithMutation(EntityManager em) {
+		super(em);
+
+		operations.add(new GqlMutationOper("insert", "This insert entity", InsertFecher.class));
+		operations.add(new GqlMutationOper("update", "This update entity", UpdateFetcher.class));
+		operations.add(new GqlMutationOper("merge", "This update entity", MergeFetcher.class));
+		operations.add(new GqlMutationOper("delete", "This delete entity", DeleteFetcher.class));
+	}
+
+	public GraphQLJpaSchemaBuilderWithMutation suffixInputObjectType(String suffixInputObjectType) {
+		this.suffixInputObjectType = suffixInputObjectType;
+		return this;
+	}
+
+	@Override
+	public GraphQLSchema build() {
+		createFetcherParams();
+		return GraphQLSchema.newSchema()
+				.query(getQueryType())
+	            .mutation(getMutation())
+	            .build();
+	}
+	
+	protected GraphQLObjectType getMutation() {
+		GraphQLObjectType.Builder queryType = 
+	        GraphQLObjectType.newObject()
+	                .name("editEntities")
+	                .description(this.getDescription());
+		
+		List<GraphQLFieldDefinition> fields = new ArrayList<>();
+
+		for (EntityType<?> entityType : entityManager.getMetamodel().getEntities()) {
+			if (!isNotIgnored(entityType)) continue;
+
+			for (GqlMutationOper oper : operations) {				
+				fields.add(getMutationDefinition(entityType, oper));
+			}
+		}
+	        
+	    queryType.fields(fields);	        			            
+	    return queryType.build();
+	}
+	
+	private GraphQLFieldDefinition getMutationDefinition(EntityType<?> entityType, GqlMutationOper oper) {		
+        return GraphQLFieldDefinition.newFieldDefinition()
+                .name(oper.getOperation()+entityType.getName())
+                .description(oper.getDescription())
+                .type(getObjectType(entityType))
+                .dataFetcher(getInputFetcher(entityType, oper))
+                .argument(getArgumentInputEntity(entityType))                
+                .build();
+    } 
+	
+	private GraphQLJpaEntityInputFetcher getInputFetcher(EntityType<?> entityType, GqlMutationOper oper) {
+		Class<? extends GraphQLJpaEntityInputFetcher> classFetch  = oper.getFetcher();
+		try {
+			return classFetch.getDeclaredConstructor(EntityManager.class, FetcherParams.class, EntityType.class)
+					.newInstance(entityManager, fetcherParams, entityType);
+		} catch(Exception e) {
+			throw new RuntimeException(e);
+		}		
+	}
+
+	
+	private GraphQLArgument getArgumentInputEntity(EntityType<?> entityType) {
+		return GraphQLArgument.newArgument()
+	        .name("entity")
+	        .type(getObjectInputType(entityType))
+	        .description("this description entity " + entityType.getName())
+	        .build();
+	}
+	
+    private GraphQLInputObjectType getObjectInputType(EntityType<?> entityType) {
+        if (entityInputCache.containsKey(entityType))
+            return entityInputCache.get(entityType);        
+        
+        GraphQLInputObjectType objectInputType = GraphQLInputObjectType.newInputObject()
+                .name(entityType.getName()+suffixInputObjectType)
+                .description("Input type GraphQL for entity "+entityType.getName())
+                
+                .fields(entityType.getAttributes().stream()
+                    .filter(this::isNotIgnored)
+                    .map(this::getObjectInputAttribute)
+                    .collect(Collectors.toList())
+                )
+                .build();
+        
+        entityInputCache.putIfAbsent(entityType, objectInputType);
+        
+        return objectInputType;
+    }
+    
+    public GraphQLInputObjectField getObjectInputAttribute(Attribute<?,?> attribute) {   
+    	GraphQLType type = getAttributeInputType(attribute);
+    	
+    	if (!(type instanceof GraphQLInputType)) {
+    		throw new IllegalArgumentException("Attribute " + attribute + " cannot be instanceof GraphQLInputType");
+    	}
+    	
+    	GraphQLInputObjectField field = GraphQLInputObjectField.newInputObjectField()
+    			.name(attribute.getName())
+    			.type((GraphQLInputType)type)    			
+    			.build();
+    	
+    	return field;
+    }
+
+    @SuppressWarnings( "rawtypes" )
+	protected GraphQLType getAttributeInputType(Attribute<?,?> attribute) {
+    	
+        if (isBasic(attribute)) {
+        	return getGraphQLTypeFromJavaType(attribute.getJavaType());        	
+        } 
+        else if (isEmbeddable(attribute)) {
+        	EmbeddableType embeddableType = (EmbeddableType) ((SingularAttribute) attribute).getType();
+        	return getEmbeddableType(embeddableType, true );
+        } 
+        else if (isToMany(attribute)) {
+            EntityType foreignType = (EntityType) ((PluralAttribute) attribute).getElementType();
+            return new GraphQLList(new GraphQLTypeReference(foreignType.getName()+suffixInputObjectType));
+        } 
+        else if (isToOne(attribute)) {
+            EntityType foreignType = (EntityType) ((SingularAttribute) attribute).getType();
+            return new GraphQLTypeReference(foreignType.getName()+suffixInputObjectType);
+        } 
+        else if (isElementCollection(attribute)) {
+            Type foreignType = ((PluralAttribute) attribute).getElementType();
+            
+            if(foreignType.getPersistenceType() == Type.PersistenceType.BASIC) {
+            	return new GraphQLList(getGraphQLTypeFromJavaType(foreignType.getJavaType()));        	
+            }
+        }
+
+        final String declaringType = attribute.getDeclaringType().getJavaType().getName(); // fully qualified name of the entity class
+        final String declaringMember = attribute.getJavaMember().getName(); // field name in the entity class
+
+        throw new UnsupportedOperationException(
+                "Attribute could not be mapped to GraphQL: field '" + declaringMember + "' of entity class '"+ declaringType +"'");
+    }
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteEntityForRole.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteEntityForRole.java
new file mode 100644
index 000000000..d6ec0318d
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteEntityForRole.java
@@ -0,0 +1,17 @@
+package com.introproventures.graphql.jpa.query.mutations.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GraphQLWriteEntityForRole {
+    String[] value();
+
+    GraphQLWriteType[] operations() default {GraphQLWriteType.ALL};
+}
+
+
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteEntityList.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteEntityList.java
new file mode 100644
index 000000000..6c4eeae44
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteEntityList.java
@@ -0,0 +1,17 @@
+package com.introproventures.graphql.jpa.query.mutations.annotation;
+
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityForRole;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GraphQLWriteEntityList {
+    GraphQLWriteEntityForRole[] value();
+}
+
+
+
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteType.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteType.java
new file mode 100644
index 000000000..374acd797
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/annotation/GraphQLWriteType.java
@@ -0,0 +1,8 @@
+package com.introproventures.graphql.jpa.query.mutations.annotation;
+
+public enum GraphQLWriteType {
+    ALL,
+    INSERT,
+    UPDATE,
+    DELETE
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/IGraphQLJpaEntityInputFetcher.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/IGraphQLJpaEntityInputFetcher.java
new file mode 100644
index 000000000..9f2b9c66c
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/IGraphQLJpaEntityInputFetcher.java
@@ -0,0 +1,7 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher;
+
+import graphql.schema.DataFetcher;
+
+public interface IGraphQLJpaEntityInputFetcher extends DataFetcher<Object> {
+    Object executeMutation(Object entity, MutationContext mutationContext);
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/MutationContext.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/MutationContext.java
new file mode 100644
index 000000000..819b5194b
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/MutationContext.java
@@ -0,0 +1,26 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MutationContext {
+    private Map<Object, List<String>> objFields = new HashMap<>();
+    private String operationName;
+
+    public String getOperationName() {
+        return operationName;
+    }
+
+    public void setOperationName(String operationName) {
+        this.operationName = operationName;
+    }
+
+    public void addContextFields(Object obj, List<String> fields) {
+        objFields.put(obj, fields);
+    }
+
+    public List<String> getObjectFields(Object obj) {
+        return objFields.get(obj);
+    }
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/DeleteFetcher.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/DeleteFetcher.java
new file mode 100644
index 000000000..9b397ff36
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/DeleteFetcher.java
@@ -0,0 +1,33 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher.impl;
+
+import com.introproventures.graphql.jpa.query.schema.ExceptionGraphQLRuntime;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.MutationContext;
+import com.introproventures.graphql.jpa.query.schema.impl.FetcherParams;
+
+import javax.persistence.EntityManager;
+import javax.persistence.metamodel.EntityType;
+
+public class DeleteFetcher extends GraphQLJpaEntityInputFetcher {
+	public DeleteFetcher(EntityManager entityManager, FetcherParams fetcherParams, EntityType<?> entityType) {
+        super(entityManager, fetcherParams, entityType);
+    }
+
+    @Override
+	public Object executeMutation(Object entity, MutationContext mutationContext) {
+
+		try {
+			Object newEntity = reloadEntityNotNull(entity);
+
+			checkAccessWriteOperation(newEntity.getClass(), GraphQLWriteType.DELETE);
+			entityManager.remove(newEntity);
+			entityManager.flush();
+
+			return reloadEntity(newEntity);
+		} catch (ExceptionGraphQLRuntime e) {
+			throw e;
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+	}
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/GraphQLJpaEntityInputFetcher.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/GraphQLJpaEntityInputFetcher.java
new file mode 100644
index 000000000..a0fa56265
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/GraphQLJpaEntityInputFetcher.java
@@ -0,0 +1,472 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher.impl;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.persistence.*;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.PluralAttribute;
+
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityForRole;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityList;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.IGraphQLJpaEntityInputFetcher;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.MutationContext;
+import com.introproventures.graphql.jpa.query.schema.ExceptionGraphQLRuntime;
+import com.introproventures.graphql.jpa.query.schema.impl.FetcherParams;
+import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaBaseFetcher;
+import graphql.language.EnumValue;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.DeserializationConfig;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.BeanDeserializer;
+import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+import graphql.schema.DataFetchingEnvironment;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class GraphQLJpaEntityInputFetcher extends GraphQLJpaBaseFetcher implements IGraphQLJpaEntityInputFetcher {
+
+	protected EntityType<?> entityType;
+
+	Logger logger = LoggerFactory.getLogger(GraphQLJpaEntityInputFetcher.class);
+
+	public static class DeserializeResult {
+	    private Object entity;
+	    private MutationContext mutationContext = new MutationContext();
+
+        public Object getEntity() {
+            return entity;
+        }
+
+        public void setEntity(Object entity) {
+            this.entity = entity;
+        }
+
+        public MutationContext getMutationContext() {
+            return mutationContext;
+        }
+    }
+	
+	public GraphQLJpaEntityInputFetcher(EntityManager entityManager, FetcherParams fetcherParams, EntityType<?> entityType) {
+        super(entityManager, fetcherParams);
+
+        this.entityType = entityType;
+    }
+
+	protected Logger getLogger() {
+		return logger;
+	}
+
+	protected void convertEnumValue(List<Object> lst) {
+		for (int i = 0; i < lst.size(); i++) {
+			Object ob = lst.get(i);
+			if (ob instanceof EnumValue) {
+				lst.add(i, ((EnumValue) ob).getName());
+			}
+			if (ob instanceof Map) {
+				convertEnumValue((Map)ob);
+			}
+			if (ob instanceof List) {
+				convertEnumValue((List)ob);
+			}
+		}
+	}
+
+	protected void convertEnumValue(Map<String, Object> mp) {
+		for (String key : mp.keySet()) {
+			Object ob = mp.get(key);
+			if (ob instanceof EnumValue) {
+				mp.put(key, ((EnumValue) ob).getName());
+			}
+			if (ob instanceof Map) {
+				convertEnumValue((Map)ob);
+			}
+			if (ob instanceof List) {
+				convertEnumValue((List)ob);
+			}
+		}
+	}
+
+
+	public DeserializeResult deserialize(DataFetchingEnvironment environment, String argument) {
+		try {
+		    DeserializeResult res = new DeserializeResult();
+
+			res.getMutationContext().setOperationName(environment.getFieldDefinition().getName());
+			Map<String, Object> mp = environment.getArgument(argument);
+			convertEnumValue(mp);
+
+			JSONObject json = new JSONObject(mp);
+
+			ObjectMapper oMapper = new ObjectMapper();
+			oMapper.registerModule(new JavaTimeModule());
+			SimpleModule module = new SimpleModule();
+		      
+		    module.setDeserializerModifier(new BeanDeserializerModifier() 
+		    {
+		      @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer)
+		      {
+		    	//custom deserialize
+		    	if (deserializer instanceof BeanDeserializer)
+		    		return new GraphQLStdDeserializer((BeanDeserializer)deserializer, res.getMutationContext());
+		    	
+		    	return deserializer;
+		      }
+		    });
+		   
+		    oMapper.registerModule(module);
+		    
+		    Object entity = oMapper.readValue(json.toString(), entityType.getJavaType());
+		    res.setEntity(entity);
+			return res;
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+	}
+
+	
+	@Override
+    public Object get(DataFetchingEnvironment environment) {
+		DeserializeResult res = deserialize(environment, "entity");
+		return executeMutation(res.getEntity(), res.getMutationContext());
+    }
+	
+	public Object reloadEntity(Object entity) {
+		if (entity == null) {
+			return null;
+		}
+		Object id = entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(entity);
+		if (id == null) {
+			return null;
+		}
+		return entityManager.find(entity.getClass(), id);
+	}
+
+	public Object reloadEntityNotNull(Object entity) {
+		if (entity == null) {
+			return null;
+		}
+
+		Object id = entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(entity);
+		if (id == null) {
+			throw new ExceptionGraphQLRuntime("Cann`t reload object "+entity.getClass().getSimpleName()+" - id not set");
+		}
+
+		Object reloadEntity = entityManager.find(entity.getClass(), id);
+
+		if (reloadEntity == null) {
+			throw new  ExceptionGraphQLRuntime("Not found object "+entity.getClass().getSimpleName() + " by id = "+id.toString());
+		}
+
+		return reloadEntity;
+	}
+
+	public EntityType<?> getEntityType() {
+		return entityType;
+	}
+
+	public EntityManager getEntityManager() {
+		return entityManager;
+	}
+
+	public void updateValueAttribute(Attribute attr, Object entity, Object newVal) {
+		updateValueAttribute(attr.getName(), entity, newVal, attr.getJavaType(), true);
+	}
+
+    public void updateValueAttribute(String attr, Object entity, Object newVal, Class<?> typeValue) {
+        updateValueAttribute(attr, entity, newVal, typeValue, true);
+    }
+
+	public void updateValueAttribute(String attr, Object entity, Object newVal, Class<?> typeValue, boolean useSetter) {
+		try {
+			String setter = "set"+StringUtils.capitalize(attr);
+			Method method = null;
+
+			try {
+			    if (!useSetter) {
+			        throw new NoSuchMethodException();
+                }
+				method = entity.getClass().getMethod(setter, typeValue);
+				method.invoke(entity, newVal);
+			} catch (NoSuchMethodException e) {
+				getLogger().warn("Access to field "+attr+" in class "+entity.getClass().getName()+". check getter");
+				Field field = entity.getClass().getDeclaredField(attr);
+				field.setAccessible(true);
+
+				field.set(entity, newVal);
+			}
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+	}
+
+	public Object getValueAttribute(Attribute attr, Object entity) {
+		return getValueAttribute(attr.getName(), entity);
+	}
+
+	public Object getValueAttribute(String attr, Object entity) {
+		try {
+			String getter = "get"+StringUtils.capitalize(attr);
+			try {
+				Method method = entity.getClass().getMethod(getter);
+				return method.invoke(entity);
+			} catch (NoSuchMethodException e) {
+				getLogger().warn("Access to field "+attr+" in class "+entity.getClass().getName()+" check getter");
+
+				Field field = entity.getClass().getDeclaredField(attr);
+				field.setAccessible(true);
+				return field.get(entity);
+			}
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+	}
+
+	public void copyEntityFields(Object source, Object dist, List<String> fields) {
+		try {
+			for (String fieldName : fields) {
+				Field field = source.getClass().getDeclaredField(fieldName);
+				field.setAccessible(true);
+				Object distField = field.get(dist);
+
+                if (distField instanceof Map) {
+
+                    ((Map) distField).clear();
+                    ((Map) distField).putAll((Map)field.get(source));
+                    continue;
+                }
+
+                if (distField instanceof Collection) {
+                    ((Collection) distField).clear();
+                    ((Collection) distField).addAll((Collection)field.get(source));
+                    continue ;
+                }
+
+				field.set(dist, field.get(source));
+			}
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+	}
+
+	public void copyEntityFields(Object source, Object dist, String field) {
+		copyEntityFields(source, dist, Arrays.asList(field));
+	}
+
+
+
+	public void reloadChildEntities(EntityType<?> et, Object entity, MutationContext mutationContext) throws Exception {
+		if (entity == null)	return ;
+
+		for (Attribute attr : et.getAttributes()) {
+			//getLogger().info("Attr = "+attr.getName());
+			Attribute.PersistentAttributeType persistType = attr.getPersistentAttributeType();
+			//OneToMany an = attr.getJavaType().getAnnotation(OneToMany.class);
+
+
+			if (persistType == Attribute.PersistentAttributeType.ONE_TO_ONE ||
+					persistType == Attribute.PersistentAttributeType.MANY_TO_ONE ) {
+				Object attrVal = getValueAttribute(attr, entity);
+				updateValueAttribute(attr, entity, reloadEntityNotNull(attrVal));
+				continue;
+			}
+
+			if (persistType == Attribute.PersistentAttributeType.ONE_TO_MANY ) {
+				Object attrVal = getValueAttribute(attr, entity);
+				if (attrVal == null) continue;
+
+				int size = 0;
+
+				if (attrVal instanceof Map) {
+					size = ((Map) attrVal).size();
+				}
+
+				if (attrVal instanceof Collection) {
+					size = ((Collection) attrVal).size();
+				}
+
+				if (size > 0) {
+					throw  new ExceptionGraphQLRuntime("For field " + attr.getName() + " cannot set objects for insert. (ONE_TO_MANY). Use operation merge or update child entity");
+				}
+
+				continue;
+			}
+
+			if (persistType == Attribute.PersistentAttributeType.MANY_TO_MANY) {
+				EntityType attrType = (EntityType) ((PluralAttribute) attr).getElementType();
+
+				String mappedBychild = null;
+				ManyToMany mtm = ((AnnotatedElement) attr.getJavaMember()).getAnnotation(ManyToMany.class);
+				if (mtm != null) {
+					mappedBychild = mtm.mappedBy();
+				}
+
+				Object attrVal = getValueAttribute(attr, entity);
+
+				Function<Object, Object> fun = new Function() {
+					private  EntityType attrType;
+					private Object parent;
+					private String mappedByChildFinal;
+
+					private Function init(EntityType attrType, Object parent, String mappedByChildFinal) {
+						this.attrType = attrType;
+						this.parent = parent;
+						this.mappedByChildFinal = mappedByChildFinal;
+						return this;
+					}
+
+					@Override
+					public Object apply(Object o) {
+						return reloadEntityMTMAndSetMappedParent(attrType, o, entity, mappedByChildFinal);
+					}
+				}.init(attrType, entity, mappedBychild);
+
+				reloadCollection(attrVal, fun);
+
+				//????
+			}
+		}
+
+	}
+
+	public Object reloadEntityMTMAndSetMappedParent(EntityType<?> et, Object entity, Object parent, String mappedBy) {
+		Object reloadEntity = reloadEntityNotNull(entity);
+
+		if (mappedBy != null && mappedBy.length() > 0) {
+			Object col = getValueAttribute(mappedBy, reloadEntity);
+			Attribute attr = et.getAttribute(mappedBy);
+			MapKey mk = ((AnnotatedElement) attr.getJavaMember()).getAnnotation(MapKey.class);
+			Object key = null;
+			if (mk != null) {
+				key = getValueAttribute(mk.name(), parent);
+			}
+
+			addManyToManyParent(col, parent, key);
+		}
+
+		return reloadEntity;
+	}
+
+	public void addManyToManyParent(Object col, Object parent, Object key) {
+		if (col instanceof Map) {
+			((Map) col).put(key, parent);
+			return;
+		}
+
+		if (col instanceof Set) {
+			((Set) col).add(parent);
+			return ;
+		}
+
+		if (col instanceof List) {
+			((List) col).add(parent);
+			return;
+		}
+
+		if (col instanceof Collection) {
+			((Collection) col).add(parent);
+			return;
+		}
+	}
+
+	public void reloadCollection(Object collection, Function<Object, Object> function) {
+		if (collection instanceof Map) {
+			((Map) collection).replaceAll((k, v) -> function.apply(v));
+			return ;
+		}
+
+		if (collection instanceof List) {
+			((List) collection).replaceAll(v -> function.apply(v));
+			return;
+		}
+
+		if (collection instanceof Collection) {
+			ArrayList<Object> array = ((Collection<Object>) collection).stream()
+					.map(v -> function.apply(v))
+					.collect(Collectors.toCollection(ArrayList::new));
+
+			((Collection<Object>) collection).clear();
+			((Collection<Object>) collection).addAll(array);
+		}
+	}
+
+	public static String getAttrMappedBy(Attribute attr) {
+        String mappedBy = null;
+        OneToMany otm = ((AnnotatedElement) attr.getJavaMember()).getAnnotation(OneToMany.class);
+        if (otm != null) {
+            mappedBy = otm.mappedBy();
+        }
+
+        ManyToMany mtm = ((AnnotatedElement) attr.getJavaMember()).getAnnotation(ManyToMany.class);
+        if (mtm != null) {
+            mappedBy = mtm.mappedBy();
+        }
+
+        OneToOne oto = ((AnnotatedElement) attr.getJavaMember()).getAnnotation(OneToOne.class);
+        if (oto != null) {
+            mappedBy = oto.mappedBy();
+        }
+
+        return mappedBy;
+    }
+
+    public static int compare(Attribute a1, Attribute a2) {
+	    String m1 = getAttrMappedBy(a1);
+        String m2 = getAttrMappedBy(a2);
+
+        if (m1 == null && m2 != null) {
+            return -1;
+        }
+
+        if (m1 != null && m2 == null) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+
+    protected boolean checkOperation(GraphQLWriteType operation, GraphQLWriteType[] operList) {
+		return Arrays.stream(operList).anyMatch(v -> v.equals(operation) || v.equals(GraphQLWriteType.ALL));
+	}
+
+	public void checkAccessWriteOperation(Class cls, GraphQLWriteType operation) {
+		if (fetcherParams.getPredicateRole() == null) {
+			return ;
+		}
+
+		AnnotatedElement annotatedElement = (AnnotatedElement)cls;
+		GraphQLWriteEntityForRole writeRoles =  annotatedElement.getAnnotation(GraphQLWriteEntityForRole.class);
+		if (writeRoles != null) {
+			if (checkOperation(operation, writeRoles.operations())) {
+				if (fetcherParams.getPredicateRole().test(writeRoles.value()))
+					return;
+			}
+		}
+
+		GraphQLWriteEntityList writeList =  annotatedElement.getAnnotation(GraphQLWriteEntityList.class);
+		if (writeList != null) {
+			for (GraphQLWriteEntityForRole wr : writeList.value()) {
+				if (checkOperation(operation, wr.operations())) {
+					if (fetcherParams.getPredicateRole().test(wr.value()))
+						return;
+				}
+			}
+		}
+
+		throw new ExceptionGraphQLRuntime("For entity "+cls.getSimpleName() + " cannot "+operation.name());
+	}
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/GraphQLStdDeserializer.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/GraphQLStdDeserializer.java
new file mode 100644
index 000000000..c904059a4
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/GraphQLStdDeserializer.java
@@ -0,0 +1,50 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher.impl;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+
+import com.fasterxml.jackson.core.JsonLocation;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.BeanDeserializer;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.MutationContext;
+
+
+public class GraphQLStdDeserializer extends BeanDeserializer implements java.io.Serializable {
+	private final BeanDeserializer defaultDeserializer;
+	private MutationContext mutationContext;
+
+	public GraphQLStdDeserializer(BeanDeserializer defaultDeserializer, MutationContext mutationContext)
+	{
+	    super(defaultDeserializer);
+	    this.defaultDeserializer = defaultDeserializer;
+	    this.mutationContext = mutationContext;
+	}
+
+	public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+		JsonLocation startLocation = p.getCurrentLocation();
+        long charOffsetStart = startLocation.getCharOffset();
+        
+        Object obj = defaultDeserializer.deserialize(p, ctxt);
+
+		JsonLocation endLocation = p.getCurrentLocation();
+        long charOffsetEnd = endLocation.getCharOffset();
+        String jsonSubString = endLocation.getSourceRef().toString().substring((int)charOffsetStart - 1, (int)charOffsetEnd);
+
+		try {
+			Map<String,Object> jsonObj =
+					new ObjectMapper().readValue(jsonSubString, HashMap.class);
+
+			mutationContext.addContextFields(obj, jsonObj.keySet().stream().collect(Collectors.toList()));
+
+			return obj;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/InsertFecher.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/InsertFecher.java
new file mode 100644
index 000000000..963176666
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/InsertFecher.java
@@ -0,0 +1,38 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher.impl;
+
+import com.introproventures.graphql.jpa.query.schema.ExceptionGraphQLRuntime;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.MutationContext;
+import com.introproventures.graphql.jpa.query.schema.impl.FetcherParams;
+
+import javax.persistence.EntityManager;
+import javax.persistence.metamodel.EntityType;
+
+public class InsertFecher extends GraphQLJpaEntityInputFetcher {
+	public InsertFecher(EntityManager entityManager, FetcherParams fetcherParams, EntityType<?> entityType) {
+        super(entityManager, fetcherParams, entityType);
+    }
+
+    @Override
+	public Object executeMutation(Object entity, MutationContext mutationContext) {
+		try {
+			reloadChildEntities(entityType, entity, mutationContext);
+
+			checkAccessWriteOperation(entity.getClass(), GraphQLWriteType.INSERT);
+			entityManager.persist(entity);
+
+			entityManager.flush();
+
+			entityManager.refresh(entity);
+
+			return entity;
+		} catch (ExceptionGraphQLRuntime e) {
+			throw e;
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+
+	}
+
+
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/MergeFetcher.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/MergeFetcher.java
new file mode 100644
index 000000000..de7d307ef
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/MergeFetcher.java
@@ -0,0 +1,194 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher.impl;
+
+import com.introproventures.graphql.jpa.query.schema.ExceptionGraphQLRuntime;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.MutationContext;
+import com.introproventures.graphql.jpa.query.schema.impl.FetcherParams;
+
+import javax.persistence.EntityManager;
+import javax.persistence.MapKey;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.PluralAttribute;
+import javax.persistence.metamodel.SingularAttribute;
+import java.lang.reflect.AnnotatedElement;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class MergeFetcher extends GraphQLJpaEntityInputFetcher {
+	public MergeFetcher(EntityManager entityManager, FetcherParams fetcherParams, EntityType<?> entityType) {
+        super(entityManager, fetcherParams, entityType);
+    }
+
+    @Override
+	public Object executeMutation(Object entity, MutationContext mutationContext) {
+
+		try {
+			Object resEntity = mergeChildEntities(entityType, entity, null, mutationContext);
+
+			//Object resEntity = entityManager.merge(entity);
+
+
+			entityManager.flush();
+
+			entityManager.refresh(resEntity);
+
+			return entity;
+		} catch (ExceptionGraphQLRuntime e) {
+			throw e;
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+	}
+
+	public Object mergeChildEntities(EntityType<?> et, Object entity, Object parent, MutationContext mutationContext) throws Exception {
+		return mergeChildEntities(et, entity, parent, mutationContext,null);
+	}
+
+
+	public Object mergeChildEntities(EntityType<?> et, Object entity, Object parent, MutationContext mutationContext, String mappedBy) throws Exception {
+		if (entity == null)	return null;
+
+		List<String> editFields = mutationContext.getObjectFields(entity);
+		if (editFields == null) return entity;
+
+		for (Attribute attr : et.getAttributes()) {
+			if (attr.getName().equals(mappedBy)) {
+				Attribute.PersistentAttributeType persistType = attr.getPersistentAttributeType();
+
+				if (persistType == Attribute.PersistentAttributeType.ONE_TO_ONE ||
+						persistType == Attribute.PersistentAttributeType.MANY_TO_ONE) {
+					updateValueAttribute(attr, entity, parent);
+					continue;
+				}
+			}
+		}
+
+		Object currentEntity = reloadEntity(entity);
+
+		Boolean isPersist = false;
+		if (currentEntity != null) {
+			copyEntityFields(entity, currentEntity, editFields);
+			entity = currentEntity;
+			checkAccessWriteOperation(entity.getClass(), GraphQLWriteType.UPDATE);
+		} else {
+			isPersist = true;
+			checkAccessWriteOperation(entity.getClass(), GraphQLWriteType.INSERT);
+		}
+
+
+        Set<Attribute> sortAttr = et.getAttributes().stream()
+                .sorted((a1, a2) -> GraphQLJpaEntityInputFetcher.compare(a1, a2) )
+                .collect(Collectors.toSet());
+
+		Map<String, Object> mappedObjects = new HashMap<>();
+
+        for (Attribute attr : sortAttr) {
+            if (editFields.indexOf(attr.getName()) >= 0 ) {
+                String mappedBychild = getAttrMappedBy(attr);
+                if (mappedBychild != null) {
+                    mappedObjects.put(attr.getName(), getValueAttribute(attr.getName(), entity));
+                    updateValueAttribute(attr.getName(), entity, null, attr.getJavaType(), false);
+                }
+            }
+        }
+
+		for (Attribute attr : et.getAttributes()) {
+
+            //getLogger().info("Attr= " + attr.getName());
+			if (editFields.indexOf(attr.getName()) >= 0 || attr.getName().equals(mappedBy)) {
+
+                String mappedBychild = getAttrMappedBy(attr);
+
+                if (isPersist && mappedBychild!=null) {
+                    entityManager.persist(entity);
+                    isPersist = false;
+                }
+
+				Attribute.PersistentAttributeType persistType = attr.getPersistentAttributeType();
+
+				//OneToMany an = attr.getJavaType().getAnnotation(OneToMany.class);
+
+				if (persistType == Attribute.PersistentAttributeType.ONE_TO_ONE ||
+					persistType == Attribute.PersistentAttributeType.MANY_TO_ONE) {
+					EntityType attrType = (EntityType) ((SingularAttribute) attr).getType();
+
+
+					if (mappedBy != null && attr.getName().equals(mappedBy)) {
+						updateValueAttribute(attr, entity, parent);
+						continue;
+					}
+
+					Object childEntity = mergeChildEntities(attrType, getValueAttribute(attr, entity), entity, mutationContext, null);
+					updateValueAttribute(attr, entity, childEntity);
+
+					continue;
+				}
+
+				if (persistType == Attribute.PersistentAttributeType.ONE_TO_MANY ||
+					persistType == Attribute.PersistentAttributeType.MANY_TO_MANY) {
+
+					EntityType attrType = (EntityType) ((PluralAttribute) attr).getElementType();
+
+					Object attrVal = null;
+					if (mappedObjects.containsKey(attr.getName())) {
+                        attrVal = mappedObjects.get(attr.getName());
+                    } else {
+                        attrVal = getValueAttribute(attr, entity);
+                    }
+
+					if (mappedBy != null && attr.getName().equals(mappedBy)) {
+						Object key = null;
+						MapKey mk = ((AnnotatedElement) attr.getJavaMember()).getAnnotation(MapKey.class);
+						if (mk != null) {
+							key = getValueAttribute(mk.name(), parent);
+						}
+						addManyToManyParent(attrVal, parent, key);
+						continue;
+					}
+					Function<Object, Object> fun = new Function() {
+						private  EntityType attrType;
+						private Object parent;
+						private String mappedByChildFinal;
+
+						private Function init(EntityType attrType, Object parent, String mappedByChildFinal) {
+							this.attrType = attrType;
+							this.parent = parent;
+							this.mappedByChildFinal = mappedByChildFinal;
+							return this;
+						}
+
+						@Override
+						public Object apply(Object obj) {
+							try {
+								return mergeChildEntities(attrType, obj, parent, mutationContext, mappedByChildFinal);
+							} catch (Exception e) {
+								throw new ExceptionGraphQLRuntime(e);
+							}
+						}
+					}.init(attrType, entity, mappedBychild);
+
+					reloadCollection(attrVal, fun);
+				}
+			}
+		}
+
+        if (isPersist) {
+            entityManager.persist(entity);
+        }
+
+        for (Attribute attr : et.getAttributes()) {
+            if (mappedObjects.containsKey(attr.getName())) {
+                updateValueAttribute(attr.getName(), entity, mappedObjects.get(attr.getName()), attr.getJavaType(), false);
+            }
+        }
+
+		//Object res =  entityManager.merge(entity);
+		//entityManager.flush();
+		return entity;
+	}
+}
diff --git a/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/UpdateFetcher.java b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/UpdateFetcher.java
new file mode 100644
index 000000000..157b66645
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/main/java/com/introproventures/graphql/jpa/query/mutations/fetcher/impl/UpdateFetcher.java
@@ -0,0 +1,43 @@
+package com.introproventures.graphql.jpa.query.mutations.fetcher.impl;
+
+import com.introproventures.graphql.jpa.query.schema.ExceptionGraphQLRuntime;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import com.introproventures.graphql.jpa.query.mutations.fetcher.MutationContext;
+import com.introproventures.graphql.jpa.query.schema.impl.FetcherParams;
+
+import javax.persistence.EntityManager;
+import javax.persistence.metamodel.EntityType;
+import java.util.List;
+
+public class UpdateFetcher extends GraphQLJpaEntityInputFetcher {
+	public UpdateFetcher(EntityManager entityManager, FetcherParams fetcherParams, EntityType<?> entityType) {
+        super(entityManager, fetcherParams, entityType);
+    }
+
+	@Override
+	public Object executeMutation(Object entity, MutationContext mutationContext) {
+		List<String> updateFields = mutationContext.getObjectFields(entity);
+
+		try {
+			reloadChildEntities(entityType, entity, mutationContext);
+
+			Object currentEntity = reloadEntity(entity);
+
+			checkAccessWriteOperation(currentEntity.getClass(), GraphQLWriteType.INSERT);
+			copyEntityFields(entity, currentEntity, updateFields);
+
+			entityManager.flush();
+
+			entityManager.refresh(currentEntity);
+
+			return currentEntity;
+		} catch (ExceptionGraphQLRuntime e) {
+			throw e;
+		} catch (Exception e) {
+			throw new ExceptionGraphQLRuntime(e);
+		}
+
+	}
+
+
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/MutationTests.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/MutationTests.java
new file mode 100644
index 000000000..96a5b17f9
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/MutationTests.java
@@ -0,0 +1,310 @@
+package com.introproventures.graphql.jpa.query.mutations;
+
+import com.introproventures.graphql.jpa.query.mutations.model.book.*;
+import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
+import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
+import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
+import graphql.ExecutionResult;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.sql.DataSource;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.NONE)
+@TestPropertySource({"classpath:hibernate.properties"})
+public class MutationTests {
+
+    static class TransactionQLExecutor {
+        @Autowired
+        private GraphQLExecutor executor;
+
+        @Transactional(propagation = Propagation.REQUIRES_NEW)
+        public ExecutionResult execute(String query) {
+            ExecutionResult res = executor.execute(query);
+            return res;
+        }
+
+        public GraphQLExecutor getExecutor() {
+            return executor;
+        }
+    }
+
+    @SpringBootApplication
+    static class Application {
+        private static String currentRole = "user";
+
+        public static String getCurrentRole() {
+            return currentRole;
+        }
+
+        public static void setCurrentRole(String currentRole) {
+            Application.currentRole = currentRole;
+        }
+
+        @Bean
+        public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {
+            return new GraphQLJpaExecutor(graphQLSchemaBuilder.build());
+        }
+
+        @Bean
+        public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) {
+            Predicate<String[]> predicateAccess = roles -> {
+                for(int i = 0; i < roles.length; i++) {
+                    if (roles[i].equals(this.currentRole)) {
+                        return true;
+                    }
+                }
+                return false;
+            };
+
+            return new GraphQLJpaSchemaBuilderWithMutation(entityManager)
+                    .predicateRole(predicateAccess)
+                    .name("GraphQLBooks")
+                    .description("Books JPA test schema");
+        }
+
+        @Bean
+        public TransactionQLExecutor transactionQLExecutor() {
+            return new TransactionQLExecutor();
+        }
+
+    }
+
+    @Autowired
+    TransactionQLExecutor transactionQLExecutor;
+
+    @PersistenceContext
+    EntityManager entityManager;
+
+    @Autowired
+    DataSource dataSource;
+
+    Logger log = LoggerFactory.getLogger(MutationTests.class);
+
+    public void checkCorrectExecutionResult(ExecutionResult result) {
+        if (result.getErrors().size() > 0) {
+            String errorMsg = result.getErrors().stream().map(Object::toString)
+                    .collect(Collectors.joining(", "));
+            throw new RuntimeException("Error graphQL result: "+errorMsg);
+        }
+    }
+
+    @Test
+    public void contextLoads() {
+        Application.setCurrentRole("user");
+
+        org.springframework.util.Assert.isAssignable(GraphQLExecutor.class, transactionQLExecutor.getExecutor().getClass());
+    }
+
+    @Test
+    public void queryInsertStudentOkWriteAccess() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  {    insertStudent(entity: {id: 46, name: \"nm\"}) {id, name} }";
+
+        String expected = "{insertStudent={id=46, name=nm}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("InsertStudent Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+    }
+
+    @Test
+    public void queryInsertStudentErrorWriteAccess() {
+        Application.setCurrentRole("test");
+
+        String query  = "mutation { insertStudent(entity: {id: 46, name: \"nm\"}) {id, name} }";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+
+        assertThat(result.getErrors())
+                .isNotEmpty()
+                .extracting("message")
+                .containsOnly(
+                        "Exception while fetching data (/insertStudent) : For entity Student cannot INSERT"
+                );
+    }
+
+    @Test
+    @Transactional
+    public void queryInsertBook() {
+        Application.setCurrentRole("user");
+
+        Author author = entityManager.find(Author.class, 1L);
+
+        String query  = "mutation  {    insertBook(" +
+                "entity: {id: 5, title: \"Shot\", author: {id: 1}, houses: [{id: 1}, {id: 2}] }) " +
+                "{id, title, genre, author{id, name, genre}, houses {id, name}} }";
+
+        String expected = "{insertBook={id=5, title=Shot, genre=null, author={id=1, name=Pushkin, genre=NOVEL}, houses=[{id=2, name=house 2}, {id=1, name=house 1}]}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("InsertBook Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+
+        Book book = entityManager.find(Book.class, 5L);
+        assertThat(book.getTitle()).isEqualTo("Shot");
+        assertThat(book.getHouses().size()).isEqualTo(2);
+    }
+
+    @Test
+    public void queryUpdateBook() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  {    updateBook(entity: {id: 2, title: \"Shot 2\", author: {id: 2}}) {id, title, genre, author{id, name, genre}} }";
+
+        String expected = "{updateBook={id=2, title=Shot 2, genre=PLAY, author={id=2, name=Lermontov, genre=PLAY}}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("UpdateBook Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+    }
+
+    @Test
+    public void queryDeleteBook() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  { deleteBook(entity: {id: 3}) {id, title} }";
+
+        String expected = "{deleteBook=null}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("DeleteBook Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+    }
+
+    @Test
+    @Transactional
+    public void queryMergeBook() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  { mergeBook(entity: {id: 40, title: \"new book\", houses: [{id: 100, name:\"new house\"}, {id: 2}]}) " +
+                "{id, title, genre, author{id, name, genre}, houses {id, name}} }";
+
+        String expected = "{mergeBook={id=40, title=new book, genre=null, author=null, houses=[{id=2, name=house 2}, {id=100, name=new house}]}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("MergeBook Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+
+
+        Book book = entityManager.find(Book.class, 40L);
+        assertThat(book.getHouses().size()).isEqualTo(2);
+        Assert.assertTrue(book.getHouses().stream().anyMatch(e -> e.getId().equals(100L)));
+        Assert.assertTrue(book.getHouses().stream().anyMatch(e -> e.getId().equals(2L)));
+
+        //delete array element
+        query  = "mutation  { mergeBook(entity: {id: 40, title: \"new book\", houses: [{id: 100, name: \"new house\"}]}) " +
+                "{id, title, genre, author{id, name, genre}, houses {id, name}} }";
+
+        expected = "{mergeBook={id=40, title=new book, genre=null, author=null, houses=[{id=100, name=new house}]}}";
+
+        result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        strRes = result.getData().toString();
+        log.info("MergeBook Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+
+        book = entityManager.find(Book.class, 40L);
+        assertThat(book.getHouses().size()).isEqualTo(2);
+        Assert.assertTrue(book.getHouses().stream().anyMatch(e -> e.getId().equals(100L)));
+    }
+
+    @Test
+    @Transactional
+    public void queryMergeHouse() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  { mergePublishingHouse(entity: {id: 400, name: \"new house\", books: [{id: 201, title:\"new book 201\"}, {id: 2}]}) " +
+                "{id, name, books{id, title, genre}} }";
+
+        String expected = "{mergePublishingHouse={id=400, name=new house, books=[{id=201, title=new book 201, genre=null}, {id=2, title=book2, genre=PLAY}]}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("MergeHouse Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+
+        PublishingHouse ph = entityManager.find(PublishingHouse.class, 400L);
+        assertThat(ph.getBooks().size()).isEqualTo(2);
+        ph.getBooks().stream().forEach(element -> System.out.println(element.getId()));
+        Assert.assertTrue(ph.getBooks().stream().anyMatch(e -> e.getId().equals(201L)));
+        Assert.assertTrue(ph.getBooks().stream().anyMatch(e -> e.getId().equals(2L)));
+    }
+
+    @Test
+    @Transactional
+    public void queryInsertAuthor() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  { insertAuthor(entity: {id: 40, name: \"qwe\",  phoneNumbers: [\"123456\", \"987654\"]}) " +
+                "{id, name, genre, phoneNumbers} }";
+
+        String expected = "{insertAuthor={id=40, name=qwe, genre=null, phoneNumbers=[123456, 987654]}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("InsertAuthor Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+
+        Author author = entityManager.find(Author.class, 40L);
+        assertThat(author.getPhoneNumbers().size()).isEqualTo(2);
+    }
+
+    @Test
+    public void queryMergeAuthor() {
+        Application.setCurrentRole("user");
+
+        String query  = "mutation  { mergeAuthor(entity: {id: 40, name: \"qwe\",  books: [{id: 100, title:\"new book\"}, {id: 2}]}) " +
+                "{id, name, genre, books {id, title}} }";
+
+        String expected = "{mergeAuthor={id=40, name=qwe, genre=null, books=[{id=100, title=new book}, {id=2, title=null}]}}";
+
+        ExecutionResult result = transactionQLExecutor.execute(query);
+        checkCorrectExecutionResult(result);
+
+        String strRes = result.getData().toString();
+        log.info("MergeAuthor Result: "+strRes);
+        assertThat(strRes).isEqualTo(expected);
+    }
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/Student.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/Student.java
new file mode 100644
index 000000000..a9f21b738
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/Student.java
@@ -0,0 +1,38 @@
+package com.introproventures.graphql.jpa.query.mutations.model;
+
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityForRole;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityList;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+@GraphQLWriteEntityList(
+        @GraphQLWriteEntityForRole(value = {"user"}, operations = {GraphQLWriteType.ALL})
+)
+public class Student {
+
+    @Id
+    private long id;
+
+    @Column(name = "name", nullable = true, length = 2000)
+    private String name;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Alias.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Alias.java
new file mode 100644
index 000000000..b23c7ba7c
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Alias.java
@@ -0,0 +1,25 @@
+package com.introproventures.graphql.jpa.query.mutations.model.book;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import javax.persistence.*;
+
+@Entity
+@Getter
+@Setter
+@ToString
+public class Alias {
+    @Id
+    Long id;
+
+    @Column(name = "name", nullable = true, length = 256)
+    String name;
+
+    @OneToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "a_id")
+    Author author;
+
+
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Author.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Author.java
new file mode 100644
index 000000000..c9356828d
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Author.java
@@ -0,0 +1,85 @@
+package com.introproventures.graphql.jpa.query.mutations.model.book;
+
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityForRole;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import javax.persistence.*;
+import java.util.*;
+
+@Entity
+@ToString
+@EqualsAndHashCode(exclude={"books","phoneNumbers"}) // Fixes NPE in Hibernate when initializing loaded collections #1
+@GraphQLWriteEntityForRole(value = {"user"}, operations = {GraphQLWriteType.ALL})
+public class Author {
+	@Id
+	Long id;
+
+	String name;
+
+	@OneToMany(mappedBy="author", fetch=FetchType.LAZY, /*cascade = CascadeType.ALL,*/ orphanRemoval=true)
+	List<Book> books = new ArrayList<>();
+	
+	@ElementCollection(fetch=FetchType.LAZY) 
+	@CollectionTable(name = "author_phone_numbers", joinColumns = @JoinColumn(name = "author_id")) 
+	@Column(name = "phone_number")
+	private Set<String> phoneNumbers = new HashSet<>();	
+	
+	@Enumerated(EnumType.STRING)
+    Genre genre;
+
+	@OneToOne(mappedBy = "author" /*, cascade = CascadeType.ALL*/,	fetch = FetchType.LAZY, optional = true)
+	private Alias alias;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public List<Book> getBooks() {
+		return books;
+	}
+
+	public void setBooks(List<Book> books) {
+        this.books.clear();
+        this.books.addAll(books);
+	}
+
+	public Set<String> getPhoneNumbers() {
+		return phoneNumbers;
+	}
+
+	public void setPhoneNumbers(Set<String> phoneNumbers) {
+		this.phoneNumbers = phoneNumbers;
+	}
+
+	public Genre getGenre() {
+		return genre;
+	}
+
+	public void setGenre(Genre genre) {
+		this.genre = genre;
+	}
+
+	public Alias getAlias() {
+		return alias;
+	}
+
+	public void setAlias(Alias alias) {
+		this.alias = alias;
+	}
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Book.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Book.java
new file mode 100644
index 000000000..1add039bc
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Book.java
@@ -0,0 +1,70 @@
+package com.introproventures.graphql.jpa.query.mutations.model.book;
+
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityForRole;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import lombok.Data;
+
+import javax.persistence.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Entity
+@GraphQLWriteEntityForRole(value = {"user"}, operations = {GraphQLWriteType.ALL})
+public class Book {
+	@Id
+	Long id;
+
+	String title;
+
+	@ManyToOne(fetch=FetchType.LAZY)
+	Author author;
+
+	@Enumerated(EnumType.STRING)
+	Genre genre;
+
+	@ManyToMany(mappedBy = "books", fetch = FetchType.EAGER/*, cascade =  CascadeType.ALL*/)
+	private Set<PublishingHouse> houses = new HashSet<>();
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public Author getAuthor() {
+		return author;
+	}
+
+	public void setAuthor(Author author) {
+		this.author = author;
+	}
+
+	public Genre getGenre() {
+		return genre;
+	}
+
+	public void setGenre(Genre genre) {
+		this.genre = genre;
+	}
+
+	public Set<PublishingHouse> getHouses() {
+		return houses;
+	}
+
+	public void setHouses(Set<PublishingHouse> houses) {
+        this.houses.clear();
+		this.houses.addAll(houses);
+	}
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Genre.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Genre.java
new file mode 100644
index 000000000..c64695982
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/Genre.java
@@ -0,0 +1,5 @@
+package com.introproventures.graphql.jpa.query.mutations.model.book;
+
+public enum Genre {
+	NOVEL, PLAY
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/PublishingHouse.java b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/PublishingHouse.java
new file mode 100644
index 000000000..d5c42bb93
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/java/com/introproventures/graphql/jpa/query/mutations/model/book/PublishingHouse.java
@@ -0,0 +1,60 @@
+package com.introproventures.graphql.jpa.query.mutations.model.book;
+
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteEntityForRole;
+import com.introproventures.graphql.jpa.query.mutations.annotation.GraphQLWriteType;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import javax.persistence.*;
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+/*
+@Getter
+@Setter
+*/
+@ToString
+@EqualsAndHashCode(exclude={"books"}) // Fixes NPE in Hibernate when initializing loaded collections #1
+@GraphQLWriteEntityForRole(value = {"user"}, operations = {GraphQLWriteType.ALL})
+public class    PublishingHouse {
+    @Id
+    Long id;
+
+    @Column(name = "name", nullable = true, length = 256)
+    String name;
+
+    @ManyToMany(fetch = FetchType.LAZY /*, cascade = CascadeType.ALL*/)
+    @JoinTable(name = "publish_book",
+            joinColumns = @JoinColumn(name = "ph_id"),
+            inverseJoinColumns = @JoinColumn(name = "b_id")
+    )
+    private List<Book> books = new ArrayList<>();
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<Book> getBooks() {
+        return books;
+    }
+
+    public void setBooks(List<Book> books) {
+        this.books.clear();
+        this.books.addAll(books);
+    }
+}
diff --git a/graphql-jpa-query-schema-mutations/src/test/resources/data.sql b/graphql-jpa-query-schema-mutations/src/test/resources/data.sql
new file mode 100644
index 000000000..d03d7a979
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/resources/data.sql
@@ -0,0 +1,24 @@
+-- Insert Code Lists
+insert into student (id, name) values
+  (1, 'org.crygier.graphql.model.starwars.Gender'),
+  (2, 'org.crygier.graphql.model.starwars.Gender');
+
+
+
+insert into author (id, name, genre) values
+  (1, 'Pushkin', 'NOVEL'),
+  (2, 'Lermontov', 'PLAY'),
+  (3, 'Tolstoy', 'PLAY');
+
+
+insert into book (id, title, author_id, genre) values
+  (1, 'book1', 1, 'NOVEL'),
+  (2, 'book2', 1, 'PLAY'),
+  (3, 'book3', 1, 'PLAY'),
+  (4, 'book4', 3, 'PLAY');
+
+
+insert into publishing_house (id, name) values
+  (1, 'house 1'),
+  (2, 'house 2');
+
diff --git a/graphql-jpa-query-schema-mutations/src/test/resources/hibernate.properties b/graphql-jpa-query-schema-mutations/src/test/resources/hibernate.properties
new file mode 100644
index 000000000..5fb4fad96
--- /dev/null
+++ b/graphql-jpa-query-schema-mutations/src/test/resources/hibernate.properties
@@ -0,0 +1,12 @@
+#spring.datasource.url = jdbc:h2:file:./testdb
+hibernate.generate_statistics=true
+org.hibernate.stat=DEBUG
+spring.jpa.properties.hibernate.show_sql=true
+spring.jpa.properties.hibernate.format_sql=true
+
+logging.level.org.hibernate.SQL=DEBUG
+logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
+
+#logging.level.org.hibernate=debug
+#logging.level.org.hibernate.type.descriptor.sql=trace
+#logging.level.org.hibernate.SQL=debug
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/ExceptionGraphQLRuntime.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/ExceptionGraphQLRuntime.java
new file mode 100644
index 000000000..393a64d2b
--- /dev/null
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/ExceptionGraphQLRuntime.java
@@ -0,0 +1,17 @@
+package com.introproventures.graphql.jpa.query.schema;
+
+public class ExceptionGraphQLRuntime extends RuntimeException {
+
+    public ExceptionGraphQLRuntime(String msg) {
+        super(msg);
+    }
+
+    public ExceptionGraphQLRuntime(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ExceptionGraphQLRuntime(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/FetcherParams.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/FetcherParams.java
new file mode 100644
index 000000000..a1c98e899
--- /dev/null
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/FetcherParams.java
@@ -0,0 +1,21 @@
+package com.introproventures.graphql.jpa.query.schema.impl;
+
+import java.util.function.Predicate;
+
+public class FetcherParams {
+    private MapEntityType mapEntityType;
+    private Predicate<String[]> predicateRole;
+
+    public FetcherParams(MapEntityType mapEntityType, Predicate<String[]> predicateRole) {
+        this.mapEntityType = mapEntityType;
+        this.predicateRole = predicateRole;
+    }
+
+    public MapEntityType getMapEntityType() {
+        return mapEntityType;
+    }
+
+    public Predicate<String[]> getPredicateRole() {
+        return predicateRole;
+    }
+}
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaBaseDataFetcher.java
similarity index 98%
rename from graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java
rename to graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaBaseDataFetcher.java
index dd42d963c..319eba9c1 100644
--- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/QraphQLJpaBaseDataFetcher.java
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaBaseDataFetcher.java
@@ -44,17 +44,7 @@
 import javax.persistence.EntityManager;
 import javax.persistence.Subgraph;
 import javax.persistence.TypedQuery;
-import javax.persistence.criteria.AbstractQuery;
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Fetch;
-import javax.persistence.criteria.From;
-import javax.persistence.criteria.Join;
-import javax.persistence.criteria.JoinType;
-import javax.persistence.criteria.Path;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import javax.persistence.criteria.Subquery;
+import javax.persistence.criteria.*;
 import javax.persistence.metamodel.Attribute;
 import javax.persistence.metamodel.Attribute.PersistentAttributeType;
 import javax.persistence.metamodel.EntityType;
@@ -84,7 +74,6 @@
 import graphql.language.StringValue;
 import graphql.language.Value;
 import graphql.language.VariableReference;
-import graphql.schema.DataFetcher;
 import graphql.schema.DataFetchingEnvironment;
 import graphql.schema.DataFetchingEnvironmentBuilder;
 import graphql.schema.GraphQLArgument;
@@ -96,13 +85,14 @@
 import graphql.util.TraversalControl;
 import graphql.util.TraverserContext;
 
+
 /**
  * Provides base implemetation for GraphQL JPA Query Data Fetchers
  *
  * @author Igor Dianov
  *
  */
-class QraphQLJpaBaseDataFetcher implements DataFetcher<Object> {
+class GraphQLJpaBaseDataFetcher extends GraphQLJpaBaseFetcher {
 
     private static final String WHERE = "where";
 
@@ -111,7 +101,6 @@ class QraphQLJpaBaseDataFetcher implements DataFetcher<Object> {
     // "__typename" is part of the graphql introspection spec and has to be ignored
     private static final String TYPENAME = "__typename";
 
-    protected final EntityManager entityManager;
     protected final EntityType<?> entityType;
     
     private boolean toManyDefaultOptional = true;
@@ -120,18 +109,21 @@ class QraphQLJpaBaseDataFetcher implements DataFetcher<Object> {
      * Creates JPA entity DataFetcher instance
      *
      * @param entityManager
+     * @param predicateRole
      * @param entityType
      */
-    public QraphQLJpaBaseDataFetcher(EntityManager entityManager, 
-                                     EntityType<?> entityType, 
+    public GraphQLJpaBaseDataFetcher(EntityManager entityManager,
+                                     FetcherParams fetcherParams,
+                                     EntityType<?> entityType,
                                      boolean toManyDefaultOptional) {
-        this.entityManager = entityManager;
+        super(entityManager, fetcherParams);
         this.entityType = entityType;
         this.toManyDefaultOptional = toManyDefaultOptional;
     }
 
     @Override
     public Object get(DataFetchingEnvironment environment) {
+        checkAccessDataFetching(environment);
         return getQuery(environment, environment.getFields().iterator().next(), true).getResultList();
     }
 
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaBaseFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaBaseFetcher.java
new file mode 100644
index 000000000..a79ab083f
--- /dev/null
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaBaseFetcher.java
@@ -0,0 +1,93 @@
+package com.introproventures.graphql.jpa.query.schema.impl;
+
+import com.introproventures.graphql.jpa.query.annotation.GraphQLReadEntityForRole;
+import graphql.execution.AbortExecutionException;
+import graphql.language.Field;
+import graphql.language.Selection;
+import graphql.language.SelectionSet;
+import graphql.schema.*;
+
+import javax.persistence.EntityManager;
+import java.lang.reflect.AnnotatedElement;
+
+public abstract class GraphQLJpaBaseFetcher implements DataFetcher<Object> {
+    protected final EntityManager entityManager;
+    protected final FetcherParams fetcherParams;
+
+    public GraphQLJpaBaseFetcher(EntityManager entityManager, FetcherParams fetcherParams) {
+        this.entityManager = entityManager;
+        this.fetcherParams = fetcherParams;
+    }
+
+    public EntityManager getEntityManager() {
+        return entityManager;
+    }
+
+    public FetcherParams getFetcherParams() {
+        return fetcherParams;
+    }
+
+    public void checkAccessDataFetching(DataFetchingEnvironment environment) {
+        if (fetcherParams.getPredicateRole() == null) {
+            return ;
+        }
+        if (environment.getFieldType() instanceof GraphQLObjectType) {
+            System.out.println(environment.getFieldType());
+            for (Field field : environment.getFields()) {
+                checkAccessSelectionFields(field.getSelectionSet(), (GraphQLObjectType) environment.getFieldType());
+            }
+        }
+    }
+
+    public boolean isReadEntity(AnnotatedElement annotatedElement) {
+        if (annotatedElement != null) {
+            GraphQLReadEntityForRole readRoles = annotatedElement.getAnnotation(GraphQLReadEntityForRole.class);
+            if (readRoles != null) {
+                return fetcherParams.getPredicateRole().test(readRoles.value());
+            }
+        }
+
+        return false;
+    }
+
+    public void checkAccessGraphQLObjectType(GraphQLType graphQLType) {
+        if (fetcherParams.getMapEntityType().existEntityType(graphQLType.getName())) {
+            Class cls = fetcherParams.getMapEntityType().getEntityType(graphQLType.getName()).getJavaType();
+
+            if (!isReadEntity(cls)) {
+                throw new RuntimeException("Read access error for entity "+graphQLType.getName());
+            }
+        }
+    }
+
+    public void checkAccessSelectionFields(SelectionSet selectionSet, GraphQLObjectType parentType) {
+        checkAccessGraphQLObjectType(parentType);
+
+        if (selectionSet == null)
+            return;
+
+        for (Selection sel :selectionSet.getSelections()) {
+            if (sel instanceof Field) {
+                Field field = (Field) sel;
+
+                GraphQLType graphQLType;
+
+
+                GraphQLFieldDefinition fieldDef = parentType.getFieldDefinition(field.getName());
+                if (fieldDef == null) {
+                    throw new AbortExecutionException("Field "+field.getName()+" not found");
+                }
+                graphQLType = fieldDef.getType();
+
+
+                if (graphQLType instanceof GraphQLList) {
+                    graphQLType = ((GraphQLList) graphQLType).getWrappedType();
+                }
+
+                if (graphQLType instanceof GraphQLObjectType) {
+                    checkAccessSelectionFields(field.getSelectionSet(), (GraphQLObjectType)graphQLType);
+                }
+            }
+        }
+    }
+}
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaOneToManyDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaOneToManyDataFetcher.java
index 4b9b2e006..bb99c59fe 100644
--- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaOneToManyDataFetcher.java
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaOneToManyDataFetcher.java
@@ -48,18 +48,21 @@ class GraphQLJpaOneToManyDataFetcher extends GraphQLJpaQueryDataFetcher {
     
     private final PluralAttribute<Object,Object,Object> attribute;
 
-    public GraphQLJpaOneToManyDataFetcher(EntityManager entityManager, 
+    public GraphQLJpaOneToManyDataFetcher(EntityManager entityManager,
+                                          FetcherParams fetcherParams,
                                           EntityType<?> entityType,
                                           boolean toManyDefaultOptional,
                                           boolean defaultDistinct,
                                           PluralAttribute<Object,Object,Object> attribute) {
-        super(entityManager, entityType, defaultDistinct, toManyDefaultOptional);
+        super(entityManager, fetcherParams, entityType, defaultDistinct, toManyDefaultOptional);
         
         this.attribute = attribute;
     }
     
     @Override
     public Object get(DataFetchingEnvironment environment) {
+        checkAccessDataFetching(environment);
+
         Field field = environment.getFields().iterator().next();
 
         Object source = environment.getSource();
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryDataFetcher.java
index 8b0bbc460..876988640 100644
--- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryDataFetcher.java
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaQueryDataFetcher.java
@@ -44,7 +44,7 @@
  * @author Igor Dianov
  *
  */
-class GraphQLJpaQueryDataFetcher extends QraphQLJpaBaseDataFetcher {
+class GraphQLJpaQueryDataFetcher extends GraphQLJpaBaseDataFetcher {
 
     private boolean defaultDistinct = true;
 	
@@ -54,15 +54,21 @@ class GraphQLJpaQueryDataFetcher extends QraphQLJpaBaseDataFetcher {
     protected static final String ORG_HIBERNATE_READ_ONLY = "org.hibernate.readOnly";
     protected static final String JAVAX_PERSISTENCE_FETCHGRAPH = "javax.persistence.fetchgraph";
 
-    private GraphQLJpaQueryDataFetcher(EntityManager entityManager, EntityType<?> entityType, boolean toManyDefaultOptional) {
-        super(entityManager, entityType, toManyDefaultOptional);
+    private GraphQLJpaQueryDataFetcher(
+            EntityManager entityManager,
+            FetcherParams fetcherParams,
+            EntityType<?> entityType,
+            boolean toManyDefaultOptional
+    ) {
+        super(entityManager, fetcherParams, entityType, toManyDefaultOptional);
     }
 
-    public GraphQLJpaQueryDataFetcher(EntityManager entityManager, 
+    public GraphQLJpaQueryDataFetcher(EntityManager entityManager,
+                                      FetcherParams fetcherParams,
                                       EntityType<?> entityType, 
                                       boolean defaultDistinct,
                                       boolean toManyDefaultOptional) {
-        super(entityManager, entityType, toManyDefaultOptional);
+        super(entityManager, fetcherParams, entityType, toManyDefaultOptional);
         this.defaultDistinct = defaultDistinct;
     }
 
@@ -76,6 +82,8 @@ public void setDefaultDistinct(boolean defaultDistinct) {
 
     @Override
     public Object get(DataFetchingEnvironment environment) {
+        checkAccessDataFetching(environment);
+
         Field field = environment.getFields().iterator().next();
         Map<String, Object> result = new LinkedHashMap<>();
 
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java
index eff118eec..a09db8681 100644
--- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSchemaBuilder.java
@@ -25,6 +25,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -105,7 +106,9 @@ public class GraphQLJpaSchemaBuilder implements GraphQLSchemaBuilder {
     
     private static final Logger log = LoggerFactory.getLogger(GraphQLJpaSchemaBuilder.class);
 
-    private EntityManager entityManager;
+    protected EntityManager entityManager;
+    protected Predicate<String[]> predicateRole;
+    protected FetcherParams fetcherParams;
      
     private String name = "GraphQLJPAQuery";
     
@@ -120,17 +123,36 @@ public GraphQLJpaSchemaBuilder(EntityManager entityManager) {
         this.entityManager = entityManager;
     }
 
+    public GraphQLJpaSchemaBuilder predicateRole(Predicate<String[]> predicateRole) {
+
+        fetcherParams = new FetcherParams(
+                new MapEntityType(entityManager),
+                predicateRole
+        );
+
+        this.predicateRole = predicateRole;
+        return this;
+    }
+
     /* (non-Javadoc)
      * @see org.activiti.services.query.qraphql.jpa.GraphQLSchemaBuilder#getGraphQLSchema()
      */
     @Override
     public GraphQLSchema build() {
+        createFetcherParams();
         return GraphQLSchema.newSchema()
             .query(getQueryType())
             .build();
     }
 
-    private GraphQLObjectType getQueryType() {
+    protected void createFetcherParams() {
+        fetcherParams = new FetcherParams(
+                new MapEntityType(entityManager),
+                predicateRole
+        );
+    }
+
+    protected GraphQLObjectType getQueryType() {
         GraphQLObjectType.Builder queryType = 
             GraphQLObjectType.newObject()
                 .name(this.name)
@@ -160,7 +182,7 @@ private GraphQLFieldDefinition getQueryFieldByIdDefinition(EntityType<?> entityT
                 .name(entityType.getName())
                 .description(getSchemaDescription(entityType))
                 .type(getObjectType(entityType))
-                .dataFetcher(new GraphQLJpaSimpleDataFetcher(entityManager, entityType, toManyDefaultOptional))
+                .dataFetcher(new GraphQLJpaSimpleDataFetcher(entityManager, fetcherParams, entityType, toManyDefaultOptional))
                 .argument(entityType.getAttributes().stream()
                     .filter(this::isValidInput)
                     .filter(this::isNotIgnored)
@@ -203,7 +225,8 @@ private GraphQLFieldDefinition getQueryFieldSelectDefinition(EntityType<?> entit
                     + "Use the '"+QUERY_SELECT_PARAM_NAME+"' field to request actual fields. "
                     + "Use the '"+ORDER_BY_PARAM_NAME+"' on a field to specify sort order for each field. ")
                 .type(pageType)
-                .dataFetcher(new GraphQLJpaQueryDataFetcher(entityManager, 
+                .dataFetcher(new GraphQLJpaQueryDataFetcher(entityManager,
+                                                            fetcherParams,
                                                             entityType, 
                                                             isDefaultDistinct, 
                                                             toManyDefaultOptional))
@@ -638,7 +661,7 @@ private GraphQLArgument getArgument(Attribute<?,?> attribute) {
                 .build();
     }
     
-    private GraphQLType getEmbeddableType(EmbeddableType<?> embeddableType, boolean input) {
+    protected GraphQLType getEmbeddableType(EmbeddableType<?> embeddableType, boolean input) {
         if (input && embeddableInputCache.containsKey(embeddableType.getJavaType()))
             return embeddableInputCache.get(embeddableType.getJavaType());
 
@@ -677,7 +700,7 @@ private GraphQLType getEmbeddableType(EmbeddableType<?> embeddableType, boolean
     }
     
 
-    private GraphQLObjectType getObjectType(EntityType<?> entityType) {
+    protected GraphQLObjectType getObjectType(EntityType<?> entityType) {
         return entityCache.computeIfAbsent(entityType, this::computeObjectType);
     }
     
@@ -773,6 +796,7 @@ else if (attribute instanceof PluralAttribute
 
             if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_MANY) {
                 dataFetcher = new GraphQLJpaOneToManyDataFetcher(entityManager,
+                                                                 fetcherParams,
                                                                  baseEntity,
                                                                  toManyDefaultOptional,
                                                                  isDefaultDistinct,
@@ -927,28 +951,28 @@ private String getSchemaDescription(EmbeddableType<?> embeddableType) {
                                  .getSchemaDescription()
                                  .orElse(null);
     }
-    
-    private boolean isNotIgnored(EmbeddableType<?> attribute) {
+
+    protected boolean isNotIgnored(EmbeddableType<?> attribute) {
         return isNotIgnored(attribute.getJavaType());
     }
-    
-    private boolean isNotIgnored(Attribute<?,?> attribute) {
+
+    protected boolean isNotIgnored(Attribute<?,?> attribute) {
         return isNotIgnored(attribute.getJavaMember()) && isNotIgnored(attribute.getJavaType());
     }
 
-    private boolean isIdentity(Attribute<?,?> attribute) {
+    protected boolean isIdentity(Attribute<?,?> attribute) {
         return attribute instanceof SingularAttribute && ((SingularAttribute<?,?>)attribute).isId();
     }
     
-    private boolean isNotIgnored(EntityType<?> entityType) {
+    protected boolean isNotIgnored(EntityType<?> entityType) {
         return isNotIgnored(entityType.getJavaType());
     }
 
-    private boolean isNotIgnored(Member member) {
+    protected boolean isNotIgnored(Member member) {
         return member instanceof AnnotatedElement && isNotIgnored((AnnotatedElement) member);
     }
 
-    private boolean isNotIgnored(AnnotatedElement annotatedElement) {
+    protected boolean isNotIgnored(AnnotatedElement annotatedElement) {
         return annotatedElement != null && annotatedElement.getAnnotation(GraphQLIgnore.class) == null;
     }
 
@@ -984,7 +1008,7 @@ protected boolean isNotIgnoredOrder(Attribute<?,?> attribute) {
 
     
     @SuppressWarnings( "unchecked" )
-    private GraphQLOutputType getGraphQLTypeFromJavaType(Class<?> clazz) {
+    protected GraphQLOutputType getGraphQLTypeFromJavaType(Class<?> clazz) {
         if (clazz.isEnum()) {
             
             if (classCache.containsKey(clazz))
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSimpleDataFetcher.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSimpleDataFetcher.java
index d690850ea..6b4265c96 100644
--- a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSimpleDataFetcher.java
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/GraphQLJpaSimpleDataFetcher.java
@@ -30,16 +30,18 @@
 import graphql.language.ObjectValue;
 import graphql.schema.DataFetchingEnvironment;
 
-class GraphQLJpaSimpleDataFetcher extends QraphQLJpaBaseDataFetcher {
+class GraphQLJpaSimpleDataFetcher extends GraphQLJpaBaseDataFetcher {
 
-    public GraphQLJpaSimpleDataFetcher(EntityManager entityManager, 
+    public GraphQLJpaSimpleDataFetcher(EntityManager entityManager,
+									   FetcherParams fetcherParams,
                                        EntityType<?> entityType,
                                        boolean toManyDefaultOptional) {
-        super(entityManager, entityType, toManyDefaultOptional);
+        super(entityManager, fetcherParams, entityType, toManyDefaultOptional);
     }
     
     @Override
     public Object get(DataFetchingEnvironment environment) {
+		checkAccessDataFetching(environment);
         
         Field field = environment.getFields().iterator().next();
 
diff --git a/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/MapEntityType.java b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/MapEntityType.java
new file mode 100644
index 000000000..7eb1d615d
--- /dev/null
+++ b/graphql-jpa-query-schema/src/main/java/com/introproventures/graphql/jpa/query/schema/impl/MapEntityType.java
@@ -0,0 +1,28 @@
+package com.introproventures.graphql.jpa.query.schema.impl;
+
+import javax.persistence.EntityManager;
+import javax.persistence.metamodel.EntityType;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapEntityType {
+    private EntityManager entityManager;
+    private Map<String, EntityType> entityTypeMap = new HashMap<>();
+
+    public MapEntityType(EntityManager entityManager) {
+        this.entityManager = entityManager;
+
+        for (EntityType entityType : entityManager.getMetamodel().getEntities()) {
+            entityTypeMap.put(entityType.getName(), entityType);
+        }
+    }
+
+    public boolean existEntityType(String name) {
+        return entityTypeMap.containsKey(name);
+    }
+
+    public EntityType getEntityType(String name) {
+        return entityTypeMap.get(name);
+    }
+
+}
diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/AccessTests.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/AccessTests.java
new file mode 100644
index 000000000..31d676f8c
--- /dev/null
+++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/AccessTests.java
@@ -0,0 +1,122 @@
+package com.introproventures.graphql.jpa.query.schema;
+
+import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
+import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;
+import graphql.ExecutionResult;
+import graphql.validation.ValidationErrorType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.persistence.EntityManager;
+
+import java.util.function.Predicate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+        webEnvironment= SpringBootTest.WebEnvironment.NONE
+)
+public class AccessTests {
+
+    @SpringBootApplication
+    static class Application {
+        private static String currentRole = "user";
+
+        public static String getCurrentRole() {
+            return currentRole;
+        }
+
+        public static void setCurrentRole(String currentRole) {
+            Application.currentRole = currentRole;
+        }
+
+        @Bean
+        public GraphQLExecutor graphQLExecutor(final GraphQLSchemaBuilder graphQLSchemaBuilder) {
+            return new GraphQLJpaExecutor(graphQLSchemaBuilder.build());
+        }
+
+        @Bean
+        public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManager entityManager) {
+
+            Predicate<String[]> predicateAccess = roles -> {
+                for(int i = 0; i < roles.length; i++) {
+                    if (roles[i].equals(this.currentRole)) {
+                        return true;
+                    }
+                }
+                return false;
+            };
+
+            return new GraphQLJpaSchemaBuilder(entityManager)
+                    .predicateRole(predicateAccess)
+                    .name("BooksExampleSchema")
+                    .description("Books Example Schema");
+        }
+
+    }
+
+
+    @Autowired
+    private GraphQLJpaSchemaBuilder builder;
+
+    @Autowired
+    private GraphQLExecutor executor;
+
+    @Before
+    public void setup() {
+    }
+
+    @Test
+    public void readErrorOperation() {
+        Application.setCurrentRole("user");
+
+        String query = "" +
+                "query { " +
+                "   Books { " +
+                "       select {" +
+                "           id title author {id}" +
+                "       } " +
+                "   } " +
+                "}";
+
+        //when
+        ExecutionResult result = executor.execute(query);
+
+        //then
+        assertThat(result.getErrors())
+                .isNotEmpty()
+                .extracting("message")
+                .containsOnly(
+                        "Exception while fetching data (/Books) : Read access error for entity Author"
+                );
+    }
+
+    @Test
+    public void readOkOperation() {
+        Application.setCurrentRole("admin");
+
+        String query = "" +
+                "query { " +
+                "   Books { " +
+                "       select {" +
+                "           id title author {id}" +
+                "       } " +
+                "   } " +
+                "}";
+
+        //when
+        ExecutionResult result = executor.execute(query);
+
+        //then
+        assertThat(result.getErrors()).isEmpty();
+
+
+    }
+}
diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/JavaScalarsTest.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/JavaScalarsTest.java
index 35f553c06..e748c0b27 100644
--- a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/JavaScalarsTest.java
+++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/JavaScalarsTest.java
@@ -19,8 +19,13 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
 
+import java.sql.Date;
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.time.*;
 import java.util.Map;
+import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
 
 import com.introproventures.graphql.jpa.query.converter.model.VariableValue;
@@ -276,4 +281,43 @@ public void string2Instant() {
         assert resultLDT.getMinute() == 15;
         assert resultLDT.getSecond() == 07;
     }
+
+    @Test
+    public void Long2SqlDate() {
+        //given
+        Coercing<?, ?> coercing = JavaScalars.of(Date.class).getCoercing();
+        final Long input = 1573294499000L;
+
+        //when
+        Object result = coercing.serialize(input);
+
+        //then
+        assertThat(result).isInstanceOf(Date.class);
+
+        Date resultLDT = (Date) result;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+        assert sdf.format(resultLDT).equals("2019-11-09") == true;
+    }
+
+    @Test
+    public void Long2SqlTimestamp() {
+        //given
+        Coercing<?, ?> coercing = JavaScalars.of(Timestamp.class).getCoercing();
+        final Long input = 1573294499000L;
+
+        //when
+        Object result = coercing.serialize(input);
+
+        //then
+        assertThat(result).isInstanceOf(Timestamp.class);
+
+        Timestamp resultLDT = (Timestamp) result;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+        System.out.println(sdf.format(resultLDT));
+
+        assert sdf.format(resultLDT).equals("2019-11-09 10:14:59") == true;
+    }
 }
diff --git a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java
index b08e3dd89..b6c0e531f 100644
--- a/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java
+++ b/graphql-jpa-query-schema/src/test/java/com/introproventures/graphql/jpa/query/schema/model/calculated/CalculatedEntity.java
@@ -7,6 +7,7 @@
 import javax.persistence.Id;
 import javax.persistence.Transient;
 
+import com.introproventures.graphql.jpa.query.annotation.GraphQLDefaultOrderBy;
 import com.introproventures.graphql.jpa.query.annotation.GraphQLDescription;
 import com.introproventures.graphql.jpa.query.annotation.GraphQLIgnore;
 
@@ -51,6 +52,7 @@ public class CalculatedEntity extends ParentCalculatedEntity {
     Long id;
 
     @GraphQLDescription("title")
+    @GraphQLDefaultOrderBy
     String title;
 
     String info;
diff --git a/pom.xml b/pom.xml
index ad05856c6..c1538d1c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,6 +43,7 @@
         <module>graphql-jpa-query-example-model-starwars</module>
         <module>graphql-jpa-query-example-model-books</module>
         <module>graphql-jpa-query-graphiql</module>
+        <module>graphql-jpa-query-schema-mutations</module>
     </modules>
 
     <distributionManagement>