diff --git a/model/src/main/java/lcsb/mapviewer/model/security/Privilege.java b/model/src/main/java/lcsb/mapviewer/model/security/Privilege.java
index d973e473a65ce25d2b491ba57acc838adbffcca2..3c9e3607bc07753b46481698898e98326eb6bd17 100644
--- a/model/src/main/java/lcsb/mapviewer/model/security/Privilege.java
+++ b/model/src/main/java/lcsb/mapviewer/model/security/Privilege.java
@@ -6,30 +6,38 @@ import java.util.Objects;
 import javax.persistence.*;
 
 @Entity
+@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "type", "object_id" }))
 public class Privilege implements Serializable {
 
   private static final long serialVersionUID = 1L;
 
-  @EmbeddedId
-  private PrivilegePK privilegePK;
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  private Integer id;
+
+  @Enumerated(EnumType.STRING)
+  private PrivilegeType type;
+
+  private Integer objectId = -1;
 
   public Privilege() {
   }
 
   public Privilege(PrivilegeType type) {
-    this.privilegePK = new PrivilegePK(type, -1);
+    this.type = type;
   }
 
   public Privilege(PrivilegeType type, Integer objectId) {
-    this.privilegePK = new PrivilegePK(type, objectId);
+    this.type = type;
+    this.objectId = objectId;
   }
 
   @Override
   public String toString() {
-    if (privilegePK.objectId.equals(-1)) {
-      return privilegePK.type.name();
+    if (isObjectPrivilege()) {
+      return type.name() + ":" + objectId;
     } else {
-      return privilegePK.type.name() + ":" + privilegePK.objectId;
+      return type.name();
     }
   }
 
@@ -38,27 +46,45 @@ public class Privilege implements Serializable {
     if (this == o) return true;
     if (!(o instanceof Privilege)) return false;
     Privilege that = (Privilege) o;
-    return Objects.equals(privilegePK, that.privilegePK);
+    return type == that.type
+        && Objects.equals(objectId, that.objectId);
   }
 
   @Override
   public int hashCode() {
-    if (privilegePK == null) return 0;
-    return privilegePK.hashCode();
+    if (isObjectPrivilege()) {
+      return Objects.hash(type, objectId);
+    } else {
+      return type.hashCode();
+    }
+  }
+
+  public boolean isObjectPrivilege() {
+    return objectId != -1;
+  }
+
+  public Integer getId() {
+    return id;
+  }
+
+  public void setId(Integer id) {
+    this.id = id;
   }
 
   public PrivilegeType getType() {
-    return privilegePK.type;
+    return type;
+  }
+
+  public void setType(PrivilegeType type) {
+    this.type = type;
   }
 
   public Integer getObjectId() {
-    return privilegePK.objectId;
+    return objectId;
   }
 
-  public boolean isObjectPrivilege() {
-    return privilegePK != null
-        && privilegePK.objectId != null
-        && !privilegePK.objectId.equals(-1);
+  public void setObjectId(Integer objectId) {
+    this.objectId = objectId;
   }
 
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/security/PrivilegePK.java b/model/src/main/java/lcsb/mapviewer/model/security/PrivilegePK.java
deleted file mode 100644
index f8a0f2e3594f6257d2d1db8177b32db80d67c019..0000000000000000000000000000000000000000
--- a/model/src/main/java/lcsb/mapviewer/model/security/PrivilegePK.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package lcsb.mapviewer.model.security;
-
-import javax.persistence.Embeddable;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import java.io.Serializable;
-import java.util.Objects;
-
-@Embeddable
-class PrivilegePK implements Serializable {
-
-  private static final long serialVersionUID = 1L;
-
-  @Enumerated(EnumType.STRING)
-  PrivilegeType type;
-
-  Integer objectId;
-
-  PrivilegePK(PrivilegeType type, Integer objectId) {
-    this.type = type;
-    this.objectId = objectId;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (!(o instanceof PrivilegePK)) return false;
-    PrivilegePK that = (PrivilegePK) o;
-    return type == that.type
-        && Objects.equals(objectId, that.objectId);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(type, objectId);
-  }
-
-}
diff --git a/model/src/main/java/lcsb/mapviewer/model/user/User.java b/model/src/main/java/lcsb/mapviewer/model/user/User.java
index 2bd610423190c5746933c4db1374fc9c0541c712..b685515b9dde39a415d9fc9d34ff77e6c81b69cf 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/User.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/User.java
@@ -70,7 +70,7 @@ public class User implements Serializable {
   @JoinTable(
       name = "user_privilege_map_table",
       joinColumns = @JoinColumn(name = "user_id"),
-      inverseJoinColumns = { @JoinColumn(name = "type"), @JoinColumn(name = "object_id") }
+      inverseJoinColumns = @JoinColumn(name = "privilege_id")
   )
   private Set<Privilege> privileges = new HashSet<>();
 
diff --git a/persist/src/main/resources/db/migration/14.0.0~alpha.0/V14.0.0.20190618__new_permission_model.sql b/persist/src/main/resources/db/migration/14.0.0~alpha.0/V14.0.0.20190618__new_permission_model.sql
index afa47a99eb215a89f18d6c12fe33180720f46fb0..5534fd15be39be5d9dae0f0f81ee41d5eb0195ff 100644
--- a/persist/src/main/resources/db/migration/14.0.0~alpha.0/V14.0.0.20190618__new_permission_model.sql
+++ b/persist/src/main/resources/db/migration/14.0.0~alpha.0/V14.0.0.20190618__new_permission_model.sql
@@ -4,56 +4,46 @@ delete from user_table where login = 'anonymous';
 alter table privilege_table rename column id_object to object_id;
 delete from privilege_table where level = 0;
 alter table privilege_table drop column level;
+alter table privilege_table drop column privilege_class_type_db;
 
+insert into privilege_table (type, object_id)
+values ('IS_ADMIN',  null);
 
-insert into privilege_table (privilege_class_type_db, type, object_id)
-values ('BASIC_PRIVILEGE', 'IS_ADMIN', -1);
-
-insert into privilege_table (privilege_class_type_db, type, object_id)
-values ('BASIC_PRIVILEGE', 'IS_CURATOR', -1);
+insert into privilege_table (type, object_id)
+values ('IS_CURATOR',  null);
 
-insert into privilege_table (privilege_class_type_db, type, object_id)
-values ('BASIC_PRIVILEGE', 'CAN_CREATE_OVERLAYS', -1);
+insert into privilege_table (type, object_id)
+values ('CAN_CREATE_OVERLAYS',  null);
 
-insert into privilege_table (privilege_class_type_db, type, object_id)
-select 'OBJECT_PRIVILEGE', 'READ_PROJECT', object_id
+insert into privilege_table (type, object_id)
+select 'READ_PROJECT', object_id
 from privilege_table where type = 'VIEW_PROJECT';
 
-insert into privilege_table (privilege_class_type_db, type, object_id)
-select 'OBJECT_PRIVILEGE', 'WRITE_PROJECT', object_id
+insert into privilege_table (type, object_id)
+select 'WRITE_PROJECT', object_id
 from privilege_table where type = 'VIEW_PROJECT';
 
-
-alter table privilege_table drop column privilege_class_type_db;
-alter table privilege_table drop column id;
-update privilege_table set object_id = -1 where object_id is null;
-alter table privilege_table add primary key (type, object_id);
-
-
 create table user_privilege_map_table (
     user_id integer not null references user_table(id),
-    type varchar not null,
-    object_id integer not null,
-    foreign key (type, object_id) references privilege_table(type, object_id)
+    privilege_id integer not null references privilege_table(id)
 );
 
-
-insert into user_privilege_map_table (user_id, type, object_id)
-select s1.user_id, s2.type, s2.object_id
+insert into user_privilege_map_table (user_id, privilege_id)
+select s1.user_id, s2.id
 from (select user_id, object_id from privilege_table where type = 'VIEW_PROJECT') s1
 inner join (select type, object_id from privilege_table where type = 'READ_PROJECT') s2
 on s1.object_id = s2.object_id;
 
-insert into user_privilege_map_table (user_id, type, object_id)
-select user_id, (select type from privilege_table where type = 'IS_ADMIN'), -1
+insert into user_privilege_map_table (user_id, privilege_id)
+select user_id, (select type from privilege_table where type = 'IS_ADMIN')
 from privilege_table where type = 'USER_MANAGEMENT';
 
-insert into user_privilege_map_table (user_id, type, object_id)
-select user_id, (select type from privilege_table where type = 'IS_CURATOR'), -1
+insert into user_privilege_map_table (user_id, privilege_id)
+select user_id, (select type from privilege_table where type = 'IS_CURATOR')
 from privilege_table where type = 'ADD_MAP';
 
-insert into user_privilege_map_table (user_id, type, object_id)
-select user_id, (select type from privilege_table where type = 'CAN_CREATE_OVERLAYS'), -1
+insert into user_privilege_map_table (user_id, privilege_id)
+select user_id, (select type from privilege_table where type = 'CAN_CREATE_OVERLAYS')
 from privilege_table where type = 'CUSTOM_LAYOUTS';
 
 delete from privilege_table where type = 'VIEW_PROJECT'
@@ -71,9 +61,10 @@ delete from privilege_table where type = 'VIEW_PROJECT'
 delete from user_privilege_map_table t1 using user_privilege_map_table t2
 where t1.CTID != t2.CTID
   and t1.user_id = t2.user_id
-  and t1.type = t2.type
-  and t1.object_id = t2.object_id;
+  and t1.privilege_id = t2.privilege_id;
 
-alter table user_privilege_map_table add primary key (user_id, type, object_id);
+alter table user_privilege_map_table add primary key (user_id, privilege_id);
 
 alter table privilege_table drop column user_id;
+
+alter table privilege_table add constraint unique_rows unique (type, object_id);
\ No newline at end of file
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
index d4e5867c215a1e01675832aa06add3673108f473..94ccdee9966039962c9687a1d5b6f27d1d18f686 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
@@ -71,11 +71,13 @@ public class UserService implements IUserService {
   @Override
   public void grantUserPrivilege(User user, Privilege privilege) {
     user.addPrivilege(privilege);
+    userDao.update(user);
   }
 
   @Override
   public void revokeUserPrivilege(User user, Privilege privilege) {
     user.removePrivilege(privilege);
+    userDao.update(user);
   }
 
   @Override
@@ -86,7 +88,7 @@ public class UserService implements IUserService {
   @Override
   public void revokeObjectDomainPrivilegesForAllUsers(PrivilegeType privilegeType, Integer objectId) {
     Privilege privilege = new Privilege(privilegeType, objectId);
-    userDao.getAll().forEach(user -> user.removePrivilege(privilege));
+    userDao.getAll().forEach(user -> revokeUserPrivilege(user, privilege));
   }
 
   @Override
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
index da7aca529928fe09c456516d054c63ee65b4ba40..6de9d64814b09ea5a55f2b0b060e1da3101696da 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
@@ -1,17 +1,57 @@
 package lcsb.mapviewer.services.impl;
 
+import lcsb.mapviewer.model.security.Privilege;
+import lcsb.mapviewer.model.security.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.persist.dao.security.PrivilegeDao;
 import lcsb.mapviewer.services.ServiceTestFunctions;
 import lcsb.mapviewer.services.interfaces.IUserService;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.Rollback;
+import org.springframework.transaction.annotation.Transactional;
 
+import static org.junit.Assert.*;
+
+@Transactional
+@Rollback(false)
 public class UserServiceTest extends ServiceTestFunctions {
 
   @Autowired
   private IUserService userService;
 
+  @Autowired
+  private PrivilegeDao privilegeDao;
+
+  @Test
+  public void grantExistingPrivilegeDoesNotProduceDuplicates() {
+    User user1 = new User();
+    user1.setLogin("test_user_1");
+    user1.setCryptedPassword("***");
+    userService.addUser(user1);
+
+    User user2 = new User();
+    user2.setLogin("test_user_2");
+    user2.setCryptedPassword("***");
+    userService.addUser(user2);
+
+    Privilege curatorPrivilege = new Privilege(PrivilegeType.IS_CURATOR);
+    if (!privilegeDao.getAll().contains(curatorPrivilege)) {
+      privilegeDao.add(curatorPrivilege);
+    }
+
+    assertFalse(userService.userHasPrivilege(user1, new Privilege(PrivilegeType.IS_CURATOR)));
+    assertFalse(userService.userHasPrivilege(user2, new Privilege(PrivilegeType.IS_CURATOR)));
+
+    userService.grantUserPrivilege(user1, new Privilege(PrivilegeType.IS_CURATOR));
+    userService.grantUserPrivilege(user2, new Privilege(PrivilegeType.IS_CURATOR));
+
+    assertTrue(userService.userHasPrivilege(user1, new Privilege(PrivilegeType.IS_CURATOR)));
+    assertTrue(userService.userHasPrivilege(user2, new Privilege(PrivilegeType.IS_CURATOR)));
+  }
+
   @Test
-  public void grantPrivilegeWorks() {
+  public void globalPrivilegeRemovalWorks() {
 
   }