diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/Article.java b/vipra-rest/src/main/java/de/vipra/rest/model/Article.java
index 54eee2bf673b768ed79033909d1ea0dda0556b69..15e9003eee3bd6479e401b4d99f871a8c7c00eeb 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/model/Article.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/model/Article.java
@@ -1,22 +1,13 @@
 package de.vipra.rest.model;
 
 import java.net.URI;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.bson.Document;
-
 public class Article extends de.vipra.util.model.Article {
 
 	private Map<String, String> links;
 
-	public Article() {}
-
-	public Article(Document document) {
-		super(document);
-	}
-
 	public Map<String, String> getLinks() {
 		return links;
 	}
@@ -32,19 +23,11 @@ public class Article extends de.vipra.util.model.Article {
 		links.put(name, link);
 	}
 
-	public void setSelf(URI base) {
+	public void setBase(URI base) {
 		URI self = uri(base);
 		if (self != null) {
 			addLink("self", self.toString());
 		}
 	}
 
-	public static ArrayList<Article> fromDocuments(final ArrayList<Document> docs) {
-		ArrayList<Article> articles = new ArrayList<Article>();
-		for (Document doc : docs) {
-			articles.add(new Article(doc));
-		}
-		return articles;
-	}
-
 }
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
index 9755629db7cf90e626a28c476527b6127e6d870b..c346a0834bec048169e82d360c5473a067ae272b 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java
@@ -39,7 +39,7 @@ public class ArticleResource {
 	public ArticleResource(@Context ServletContext servletContext) throws ConfigException, IOException {
 		Config config = new Config();
 		Mongo mongo = Mongo.getInstance(config);
-		service = new ArticleService(mongo.getDatabase());
+		service = new ArticleService(mongo);
 	}
 
 	@GET
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java
index fef599531f1d1b5c172c4e14866b1ffc65a86673..14c531038b1b9334e97e699ef9ecc4504439a6cd 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleDeserializer.java
@@ -10,7 +10,7 @@ import com.fasterxml.jackson.databind.JsonNode;
 
 import de.vipra.rest.model.Article;
 
-import static de.vipra.rest.serializer.Helper.*;
+import static de.vipra.rest.serializer.JsonHelper.*;
 
 public class ArticleDeserializer extends JsonDeserializer<Article> {
 
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java
index a248288e9fecd3ca81ccc4c7e3311260bbdcc08a..c241ce97af969b4acb6954d8e0cf4e9b27ed77b3 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/serializer/ArticleSerializer.java
@@ -9,7 +9,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 
-import static de.vipra.rest.serializer.Helper.*;
+import static de.vipra.rest.serializer.JsonHelper.*;
 
 public class ArticleSerializer extends JsonSerializer<Article> {
 
diff --git a/vipra-rest/src/main/java/de/vipra/rest/serializer/Helper.java b/vipra-rest/src/main/java/de/vipra/rest/serializer/JsonHelper.java
similarity index 98%
rename from vipra-rest/src/main/java/de/vipra/rest/serializer/Helper.java
rename to vipra-rest/src/main/java/de/vipra/rest/serializer/JsonHelper.java
index d4d04f45134cb92c2b82c8ca94d6dc679f257e06..10bfca3a60b0e2f7f716515519407f76cf96f96c 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/serializer/Helper.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/serializer/JsonHelper.java
@@ -7,7 +7,7 @@ import java.util.Date;
 
 import com.fasterxml.jackson.databind.JsonNode;
 
-public class Helper {
+public class JsonHelper {
 
 	public static <T> T get(JsonNode node, String name, T defaultValue, Class<T> type) {
 		if (node == null) {
diff --git a/vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java b/vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java
index 4d98db3203c54822a9ca1ad887ffd47754c79bb8..09444254534b927ad9ca529124afeaaca741f2a6 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java
+++ b/vipra-rest/src/main/java/de/vipra/rest/service/ArticleService.java
@@ -3,69 +3,49 @@ package de.vipra.rest.service;
 import java.net.URI;
 import java.util.ArrayList;
 
-import org.bson.Document;
-
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoDatabase;
-import com.mongodb.client.model.Filters;
-import com.mongodb.client.result.DeleteResult;
-import com.mongodb.client.result.UpdateResult;
-
 import de.vipra.rest.model.Article;
+import de.vipra.util.Mongo;
+import de.vipra.util.service.ModelService;
 
-import static de.vipra.rest.resource.Helper.*;
-
-public class ArticleService {
-
-	final MongoCollection<Document> articles;
+public class ArticleService extends ModelService<Article> {
 
-	public ArticleService(MongoDatabase db) {
-		articles = db.getCollection("articles");
+	public ArticleService(Mongo mongo) {
+		super(mongo, "articles", Article.class);
 	}
 
 	public Article getArticle(URI base, String id) {
-		ArrayList<Document> result = articles.find(Filters.eq("_id", objectId(id))).into(new ArrayList<Document>());
-		if (result.size() == 1) {
-			Article article = new Article(result.get(0));
-			article.setSelf(base);
-			return article;
-		} else {
-			return null;
+		Article article = super.getSingle(id);
+		if (article != null) {
+			article.setBase(base);
 		}
+		return article;
 	}
 
 	public ArrayList<Article> getArticles(URI base, int skip, int limit, String sortBy) {
-
-		ArrayList<Document> docs = articles.find().skip(skip).limit(limit).sort(getSorts(sortBy))
-				.into(new ArrayList<Document>());
-		ArrayList<Article> result = Article.fromDocuments(docs);
-		for (Article article : result) {
+		ArrayList<Article> articles = super.getMultiple(skip, limit, sortBy);
+		for (Article article : articles) {
 			article.setText(null);
-			article.setSelf(base);
+			article.setBase(base);
 		}
-		return result;
+		return articles;
 	}
 
 	public Article createArticle(URI base, Article article) {
-		Document doc = new Document(article.toDocument());
-		articles.insertOne(doc);
-		article = new Article(doc);
-		article.setSelf(base);
+		article = super.createSingle(article);
+		if (article != null) {
+			article.setBase(base);
+		}
 		return article;
 	}
 
 	public long deleteArticle(String id) {
-		DeleteResult result = articles.deleteOne(Filters.eq("_id", objectId(id)));
-		return result.getDeletedCount();
+		return super.deleteSingle(id);
 	}
 
 	public long updateArticle(URI base, Article article) {
-		Document docOld = new Document("_id", objectId(article.getId()));
-		Document docNew = article.toDocument();
-		UpdateResult result = articles.replaceOne(docOld, docNew);
-		article.fromDocument(docNew);
-		article.setSelf(base);
-		return result.getModifiedCount();
+		long updated = super.updateSingle(article);
+		article.setBase(base);
+		return updated;
 	}
 
 }
diff --git a/vipra-util/.classpath b/vipra-util/.classpath
index d38d831c96760fdab9ce81082bb658d298932a2c..8e8834b85c6119993d8a437a28cc84a03dbd4179 100644
--- a/vipra-util/.classpath
+++ b/vipra-util/.classpath
@@ -2,16 +2,16 @@
 <classpath>
 	<classpathentry kind="src" path="src/main/java"/>
 	<classpathentry kind="src" path="src/main/resources"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+	<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
 		<attributes>
-			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="owner.project.facets" value="java"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>
diff --git a/vipra-util/.settings/org.eclipse.jdt.core.prefs b/vipra-util/.settings/org.eclipse.jdt.core.prefs
index b57afe22e4855dd1b5f89346a1983ffbb135152c..0f67aafb9462a60cfdb12a1efb87599393e417e4 100644
--- a/vipra-util/.settings/org.eclipse.jdt.core.prefs
+++ b/vipra-util/.settings/org.eclipse.jdt.core.prefs
@@ -1,15 +1,15 @@
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.source=1.8
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml b/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml
index 926884d914bf20b850efed694a328543aa498e30..78e8ebb782bd149152a876e5c227156f0192bd2a 100644
--- a/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml
+++ b/vipra-util/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -2,6 +2,6 @@
 <faceted-project>
   <fixed facet="jst.utility"/>
   <fixed facet="java"/>
-  <installed facet="java" version="1.6"/>
   <installed facet="jst.utility" version="1.0"/>
+  <installed facet="java" version="1.8"/>
 </faceted-project>
diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/Helper.java b/vipra-util/src/main/java/de/vipra/util/helper/MongoHelper.java
similarity index 83%
rename from vipra-rest/src/main/java/de/vipra/rest/resource/Helper.java
rename to vipra-util/src/main/java/de/vipra/util/helper/MongoHelper.java
index 14037482fbb3d0ee7eadaa0222b5b4f7f4ad9007..5b39e776c590ae5c2f96f51749f1e860deebec66 100644
--- a/vipra-rest/src/main/java/de/vipra/rest/resource/Helper.java
+++ b/vipra-util/src/main/java/de/vipra/util/helper/MongoHelper.java
@@ -1,17 +1,17 @@
-package de.vipra.rest.resource;
-
-import static com.mongodb.client.model.Sorts.*;
+package de.vipra.util.helper;
 
 import java.util.ArrayList;
 
 import org.bson.conversions.Bson;
 import org.bson.types.ObjectId;
 
-public class Helper {
+import static com.mongodb.client.model.Sorts.*;
+
+public class MongoHelper {
 
 	public static Bson getSorts(String sortBy) {
 		String[] sortKeys = sortBy.split(",");
-		ArrayList<Bson> sorts = new ArrayList<>(sortKeys.length);
+		ArrayList<Bson> sorts = new ArrayList<Bson>(sortKeys.length);
 		for (String sort : sortKeys) {
 			if (sort.startsWith("-")) {
 				sorts.add(descending(sort.substring(1)));
diff --git a/vipra-util/src/main/java/de/vipra/util/model/Article.java b/vipra-util/src/main/java/de/vipra/util/model/Article.java
index a784d993105ef1fbcf283aaec923227c67154b99..77d2d07dd25b6db5ae1f1cee275c5d82c6646b79 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/Article.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/Article.java
@@ -12,15 +12,6 @@ public class Article extends Model {
 	private String url;
 	private Date date;
 
-	public Article() {
-		super(Article.class);
-	}
-
-	public Article(Document document) {
-		this();
-		fromDocument(document);
-	}
-
 	public String getTitle() {
 		return title;
 	}
@@ -53,6 +44,11 @@ public class Article extends Model {
 		this.date = date;
 	}
 
+	public String getType() {
+		return Article.class.getSimpleName().toLowerCase();
+	}
+
+	@Override
 	public Document toDocument() {
 		Document doc = new Document("title", title).append("text", text).append("url", url).append("date", date);
 		if (getId() != null) {
@@ -61,6 +57,7 @@ public class Article extends Model {
 		return doc;
 	}
 
+	@Override
 	public void fromDocument(Document document) {
 		setId(document.getObjectId("_id").toString());
 		setTitle(document.getString("title"));
diff --git a/vipra-util/src/main/java/de/vipra/util/model/Model.java b/vipra-util/src/main/java/de/vipra/util/model/Model.java
index a8078a513b112e17ecd551c95ca2dc687f69e948..77073b12997982363ddd51b1aa96578854bc5fe2 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/Model.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/Model.java
@@ -3,13 +3,16 @@ package de.vipra.util.model;
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.bson.Document;
+
 public abstract class Model {
 
 	private String id;
-	private final String type;
 
-	public Model(Class<?> clazz) {
-		this.type = clazz.getSimpleName().toLowerCase();
+	public Model() {}
+
+	public Model(Document document) {
+		fromDocument(document);
 	}
 
 	public String getId() {
@@ -20,10 +23,6 @@ public abstract class Model {
 		this.id = id;
 	}
 
-	public String getType() {
-		return type;
-	}
-
 	public URI uri(URI base) {
 		try {
 			return new URI(base.toString() + "/" + getId());
@@ -32,4 +31,10 @@ public abstract class Model {
 		}
 	}
 
+	public abstract String getType();
+
+	public abstract void fromDocument(Document document);
+
+	public abstract Document toDocument();
+
 }
diff --git a/vipra-util/src/main/java/de/vipra/util/service/ModelService.java b/vipra-util/src/main/java/de/vipra/util/service/ModelService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d24a0b71046490876a13adfd230001c1ebe6b480
--- /dev/null
+++ b/vipra-util/src/main/java/de/vipra/util/service/ModelService.java
@@ -0,0 +1,84 @@
+package de.vipra.util.service;
+
+import static de.vipra.util.helper.MongoHelper.getSorts;
+import static de.vipra.util.helper.MongoHelper.objectId;
+
+import java.util.ArrayList;
+
+import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.result.DeleteResult;
+import com.mongodb.client.result.UpdateResult;
+
+import de.vipra.util.Mongo;
+import de.vipra.util.model.Model;
+
+public class ModelService<T extends Model> {
+
+	private static final Logger log = LoggerFactory.getLogger(ModelService.class);
+
+	private final MongoCollection<Document> collection;
+	private final Class<T> clazz;
+
+	public ModelService(Mongo mongo, String collectionName, Class<T> clazz) {
+		this.collection = mongo.getDatabase().getCollection(collectionName);
+		this.clazz = clazz;
+	}
+
+	private T newT(Document document) {
+		try {
+			T t = clazz.newInstance();
+			t.fromDocument(document);
+			return t;
+		} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | SecurityException e) {
+			log.error(e.getMessage());
+			return null;
+		}
+	}
+
+	protected T getSingle(String id) {
+		ArrayList<Document> result = collection.find(Filters.eq("_id", objectId(id))).into(new ArrayList<Document>());
+		if (result.size() == 1) {
+			return newT(result.get(0));
+		} else {
+			return null;
+		}
+	}
+
+	protected ArrayList<T> getMultiple(int skip, int limit, String sortBy) {
+		ArrayList<Document> documents = collection.find().skip(skip).limit(limit).sort(getSorts(sortBy))
+				.into(new ArrayList<Document>());
+		ArrayList<T> items = new ArrayList<>(documents.size());
+
+		for (Document document : documents) {
+			items.add(newT(document));
+		}
+
+		return items;
+	}
+
+	protected T createSingle(T t) {
+		Document document = new Document(t.toDocument());
+		collection.insertOne(document);
+		t.fromDocument(document);
+		return t;
+	}
+
+	protected long deleteSingle(String id) {
+		DeleteResult result = collection.deleteOne(Filters.eq("_id", objectId(id)));
+		return result.getDeletedCount();
+	}
+
+	protected long updateSingle(T t) {
+		Document docOld = new Document("_id", objectId(t.getId()));
+		Document docNew = t.toDocument();
+		UpdateResult result = collection.replaceOne(docOld, docNew);
+		t.fromDocument(docNew);
+		return result.getModifiedCount();
+	}
+
+}