diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/LinkedUserProfileResource.java b/goofy-server/src/main/java/de/itvsh/goofy/common/LinkedUserProfileResource.java
index 0eb257fcd5fbf02d84f840cc09d373086632cfb0..45f83c9bd99d426945c9bdb944a9bd84c13be7f5 100644
--- a/goofy-server/src/main/java/de/itvsh/goofy/common/LinkedUserProfileResource.java
+++ b/goofy-server/src/main/java/de/itvsh/goofy/common/LinkedUserProfileResource.java
@@ -18,9 +18,8 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 @JsonSerialize(using = LinkedUserProfileResourceSerializer.class)
 @JsonDeserialize(using = LinkedUserProfileResourceDeserializer.class)
 public @interface LinkedUserProfileResource {
-	Class<? extends IdExtractor<Object>> extractor()
 
-	default ToStringExtractor.class;
+	Class<? extends IdExtractor<Object>> extractor() default ToStringExtractor.class;
 
 	Class<? extends ObjectBuilder<Object>> builder() default IdBuilder.class;
 }
diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/ModelBuilder.java b/goofy-server/src/main/java/de/itvsh/goofy/common/ModelBuilder.java
index 4b54af83ff9c81cd85efef0bf52abf4789d2d9e9..99764401b87bc5e96ce02d21112d1f12745d2edd 100644
--- a/goofy-server/src/main/java/de/itvsh/goofy/common/ModelBuilder.java
+++ b/goofy-server/src/main/java/de/itvsh/goofy/common/ModelBuilder.java
@@ -4,6 +4,8 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -22,6 +24,7 @@ import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
+import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
 
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
@@ -29,7 +32,7 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class ModelBuilder<T> {
 
-	private static final Map<Class<?>, List<Field>> ANNOTATED_FIELDS = new ConcurrentHashMap<>();
+	private static final Map<Class<?>, Map<Object, List<Field>>> ANNOTATED_FIELDS_BY_ANNOTATION = new ConcurrentHashMap<>();
 
 	private final T entity;
 	private final EntityModel<T> model;
@@ -88,7 +91,9 @@ public class ModelBuilder<T> {
 
 		EntityModel<T> buildedModel = Objects.isNull(model) ? EntityModel.of(entity) : model;
 		buildedModel = buildedModel.add(filteredLinks);
-		addLinkByAnnotationIfMissing(buildedModel, LinkedResource.class, LinkedUserProfileResource.class);
+
+		addLinkByLinkedResourceAnnotationIfMissing(buildedModel);
+		addLinkByLinkedUserProfileResourceAnnotationIfMissing(buildedModel);
 
 		return applyMapper(buildedModel);
 	}
@@ -102,29 +107,50 @@ public class ModelBuilder<T> {
 		return result;
 	}
 
-	private T getEntity() {
-		return Optional.ofNullable(entity == null ? model.getContent() : entity)
-				.orElseThrow(() -> new IllegalStateException("Entity must not null for ModelBuilding"));
+	private void addLinkByLinkedResourceAnnotationIfMissing(EntityModel<T> resource) {
+		getFields(LinkedResource.class).stream()
+				.filter(field -> shouldAddLink(resource, field))
+				.forEach(field -> handleLinkedResourceField(resource, field));
 	}
 
-	@SafeVarargs
-	private void addLinkByAnnotationIfMissing(EntityModel<T> resource, Class<? extends Annotation>... annotationClasses) {
-		Arrays.stream(annotationClasses).forEach(annotation -> {
-			var fields = ANNOTATED_FIELDS.get(getEntity().getClass());
-			if (CollectionUtils.isEmpty(fields)) {
-				fields = FieldUtils.getFieldsListWithAnnotation(getEntity().getClass(), annotation);
-				ANNOTATED_FIELDS.put(getEntity().getClass(), fields);
-			}
+	private void handleLinkedResourceField(EntityModel<T> resource, Field field) {
+		getEntityFieldValue(field).ifPresent(val -> resource
+				.add(WebMvcLinkBuilder.linkTo(field.getAnnotation(LinkedResource.class).controllerClass()).slash(val)
+						.withRel(sanitizeName(field.getName()))));
+	}
 
-			fields.forEach(field -> {
-				String fieldName = sanitizeName(field.getName());
-				if (field.getType().isArray() || Collection.class.isAssignableFrom(field.getType()) || resource.hasLink(fieldName)) {
-					return;
-				}
+	private void addLinkByLinkedUserProfileResourceAnnotationIfMissing(EntityModel<T> resource) {
+		getFields(LinkedUserProfileResource.class).stream()
+				.filter(field -> shouldAddLink(resource, field))
+				.forEach(field -> handleLinkedUserProfileResourceField(resource, field));
+	}
+
+	private void handleLinkedUserProfileResourceField(EntityModel<T> resource, Field field) {
+		getEntityFieldValue(field).ifPresent(val -> resource.add(Link.of(UserProfileUrlProvider.getUrl(val)).withRel(sanitizeName(field.getName()))));
+	}
 
-				getEntityFieldValue(field).ifPresent(val -> resource.add(Link.of(UserProfileUrlProvider.getUrl(val)).withRel(fieldName)));
-			});
-		});
+	private boolean shouldAddLink(EntityModel<T> resource, Field field) {
+		return !(field.getType().isArray() || Collection.class.isAssignableFrom(field.getType()) || resource.hasLink(sanitizeName(field.getName())));
+	}
+
+	private List<Field> getFields(Class<? extends Annotation> annotationClass) {
+		var fields = Optional.ofNullable(ANNOTATED_FIELDS_BY_ANNOTATION.get(getEntity().getClass()))
+				.map(fieldsByAnnotation -> fieldsByAnnotation.get(annotationClass))
+				.orElseGet(() -> Collections.emptyList());
+
+		if (CollectionUtils.isEmpty(fields)) {
+			fields = FieldUtils.getFieldsListWithAnnotation(getEntity().getClass(), annotationClass);
+
+			updateFields(annotationClass, fields);
+		}
+		return fields;
+	}
+
+	private void updateFields(Class<? extends Annotation> annotationClass, List<Field> fields) {
+		var annotationMap = Optional.ofNullable(ANNOTATED_FIELDS_BY_ANNOTATION.get(getEntity().getClass())).orElseGet(HashMap::new);
+		annotationMap.put(annotationClass, fields);
+
+		ANNOTATED_FIELDS_BY_ANNOTATION.put(annotationClass, annotationMap);
 	}
 
 	private String sanitizeName(String fieldName) {
@@ -146,6 +172,11 @@ public class ModelBuilder<T> {
 		return Optional.empty();
 	}
 
+	private T getEntity() {
+		return Optional.ofNullable(entity == null ? model.getContent() : entity)
+				.orElseThrow(() -> new IllegalStateException("Entity must not null for ModelBuilding"));
+	}
+
 	@RequiredArgsConstructor
 	public class ConditionalLinkAdder {
 
diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/ModelBuilderTest.java b/goofy-server/src/test/java/de/itvsh/goofy/common/ModelBuilderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..658f4214b10359dba4cee7658f40f1a235f48f2e
--- /dev/null
+++ b/goofy-server/src/test/java/de/itvsh/goofy/common/ModelBuilderTest.java
@@ -0,0 +1,92 @@
+package de.itvsh.goofy.common;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.env.Environment;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import lombok.Builder;
+
+class ModelBuilderTest {
+
+	@DisplayName("Add link by annotation if missing")
+	@Nested
+	class TestAddLinkByAnnotationIfMissing {
+
+		private static final String USER_MANAGER_URL = "http://localhost";
+		private static final String USER_MANAGER_PROFILE_TEMPLATE = "/api/profile/%s";
+
+		private UserProfileUrlProvider provider = new UserProfileUrlProvider();
+
+		@Mock
+		private ApplicationContext context;
+		@Mock
+		private Environment env;
+
+		private TestEntity entity = TestEntityTestFactory.create();
+
+		@BeforeEach
+		void mockEnvironment() {
+			when(env.getProperty(UserProfileUrlProvider.URL_ROOT_KEY)).thenReturn(USER_MANAGER_URL);
+			when(env.getProperty(UserProfileUrlProvider.USER_PROFILES_TEMPLATE_KEY)).thenReturn(USER_MANAGER_PROFILE_TEMPLATE);
+			when(context.getEnvironment()).thenReturn(env);
+
+			provider.setApplicationContext(context);
+		}
+
+		@Test
+		void shouldHaveAddLinkByLinkedResource() {
+			var model = ModelBuilder.fromEntity(entity).buildModel();
+
+			assertThat(model.getLink(TestController.FILE_REL).get().getHref()).isEqualTo("/api/test/" + TestEntityTestFactory.FILE);
+		}
+
+		@Test
+		void shouldHaveAddLinkByLinkedUserProfileResource() {
+			var model = ModelBuilder.fromEntity(entity).buildModel();
+
+			assertThat(model.getLink(TestController.USER_REL).get().getHref())
+					.isEqualTo(String.format(USER_MANAGER_URL + USER_MANAGER_PROFILE_TEMPLATE, TestEntityTestFactory.USER));
+		}
+	}
+}
+
+@Builder
+class TestEntity {
+
+	@LinkedResource(controllerClass = TestController.class)
+	private String file;
+
+	@LinkedUserProfileResource
+	private String user;
+}
+
+@RequestMapping("/api/test")
+class TestController {
+
+	static final String USER_REL = "user";
+	static final String FILE_REL = "file";
+
+}
+
+class TestEntityTestFactory {
+
+	static final String USER = UUID.randomUUID().toString();
+	static final String FILE = UUID.randomUUID().toString();
+
+	public static TestEntity create() {
+		return TestEntity.builder()
+				.file(FILE)
+				.user(USER)
+				.build();
+	}
+}
diff --git a/goofy-server/src/test/java/de/itvsh/goofy/wiedervorlage/WiedervorlageControllerITCase.java b/goofy-server/src/test/java/de/itvsh/goofy/wiedervorlage/WiedervorlageControllerITCase.java
index 93bdce9cb73cfbeda48d710fe2dc52e27c2d3db8..b3d22fb76f5a9d886d1909fec28df0230c8688d8 100644
--- a/goofy-server/src/test/java/de/itvsh/goofy/wiedervorlage/WiedervorlageControllerITCase.java
+++ b/goofy-server/src/test/java/de/itvsh/goofy/wiedervorlage/WiedervorlageControllerITCase.java
@@ -74,6 +74,8 @@ public class WiedervorlageControllerITCase {
 				var response = callEndpoint();
 
 				response.andDo(print())
+						.andExpect(jsonPath("$._links.self").exists())
+						.andExpect(jsonPath("$._links.createdBy").exists())
 						.andExpect(jsonPath("$.createdAt").value(WiedervorlageTestFactory.CREATED_AT_STR))
 						.andExpect(jsonPath("$.frist").value(WiedervorlageTestFactory.FRIST.atStartOfDay().format(DateTimeFormatter.ISO_DATE_TIME)));
 			}