diff --git a/modules/quiz_directions/src/Plugin/quiz/QuizQuestion/QuizDirectionsQuestion.php b/modules/quiz_directions/src/Plugin/quiz/QuizQuestion/QuizDirectionsQuestion.php
index af5b7039dc29b243e1dee84d735ddc58f9a87820..cca479ca8197d692d5f77f84bac12e6d3880b886 100644
--- a/modules/quiz_directions/src/Plugin/quiz/QuizQuestion/QuizDirectionsQuestion.php
+++ b/modules/quiz_directions/src/Plugin/quiz/QuizQuestion/QuizDirectionsQuestion.php
@@ -3,11 +3,12 @@
 namespace Drupal\quiz_directions\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 
 /**
- * @file
  * Quiz_directions classes.
  *
  * This module uses the question interface to define something which is
@@ -20,15 +21,12 @@ use Drupal\quiz\Entity\QuizResultAnswer;
  *     please..." (Won't work if the question order is randomized);
  *   - Final confirmation, e.g. "You have answered all questions. Click submit
  *     to submit this quiz.";
- *
- * @QuizQuestion (
- *   id = "directions",
- *   label = @Translation("Directions question"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_directions\Plugin\quiz\QuizQuestion\QuizDirectionsResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'directions',
+  label: new TranslatableMarkup('Directions question'),
+  handlers: ['response' => QuizDirectionsResponse::class],
+)]
 class QuizDirectionsQuestion extends QuizQuestion {
 
   /**
diff --git a/modules/quiz_long_answer/src/Plugin/quiz/QuizQuestion/LongAnswerQuestion.php b/modules/quiz_long_answer/src/Plugin/quiz/QuizQuestion/LongAnswerQuestion.php
index 670769dc19a4835135b01e3bcb191eb5850707eb..8648c3e30a6b93ce0f96b9cd4ccb471f6a94bac9 100644
--- a/modules/quiz_long_answer/src/Plugin/quiz/QuizQuestion/LongAnswerQuestion.php
+++ b/modules/quiz_long_answer/src/Plugin/quiz/QuizQuestion/LongAnswerQuestion.php
@@ -4,21 +4,20 @@ namespace Drupal\quiz_long_answer\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 use function filter_default_format;
 
 /**
  * Long Answer Quiz Question.
- *
- * @QuizQuestion (
- *   id = "long_answer",
- *   label = @Translation("Long answer question"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_long_answer\Plugin\quiz\QuizQuestion\LongAnswerResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'Translation',
+  label: new TranslatableMarkup('Long answer question'),
+  handlers: ['response' => LongAnswerResponse::class],
+)]
 class LongAnswerQuestion extends QuizQuestion {
 
   use StringTranslationTrait;
diff --git a/modules/quiz_matching/src/Plugin/quiz/QuizQuestion/MatchingQuestion.php b/modules/quiz_matching/src/Plugin/quiz/QuizQuestion/MatchingQuestion.php
index 841de577189031c563db7874ab4cb660fb02c613..3693882552cca5ebc7e2b65dfb709889ecd22c11 100644
--- a/modules/quiz_matching/src/Plugin/quiz/QuizQuestion/MatchingQuestion.php
+++ b/modules/quiz_matching/src/Plugin/quiz/QuizQuestion/MatchingQuestion.php
@@ -4,6 +4,8 @@ namespace Drupal\quiz_matching\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 
@@ -14,15 +16,12 @@ use Drupal\quiz\Entity\QuizResultAnswer;
  *
  * A Matching node defines a series of questions and answers and requires the
  * userto associate each answer with a question.
- *
- * @QuizQuestion (
- *   id = "matching",
- *   label = @Translation("Matching question"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_matching\Plugin\quiz\QuizQuestion\MatchingResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'matching',
+  label: new TranslatableMarkup('Matching question'),
+  handlers: ['response' => MatchingResponse::class],
+)]
 class MatchingQuestion extends QuizQuestion {
 
   use StringTranslationTrait;
diff --git a/modules/quiz_multichoice/src/Plugin/quiz/QuizQuestion/MultichoiceQuestion.php b/modules/quiz_multichoice/src/Plugin/quiz/QuizQuestion/MultichoiceQuestion.php
index 54d81e2915ae885d204f94ab1c88534f014c1dbd..d8bbe070d08c8488ec59bc859c081e5add9958cd 100644
--- a/modules/quiz_multichoice/src/Plugin/quiz/QuizQuestion/MultichoiceQuestion.php
+++ b/modules/quiz_multichoice/src/Plugin/quiz/QuizQuestion/MultichoiceQuestion.php
@@ -4,22 +4,21 @@ namespace Drupal\quiz_multichoice\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 use function check_markup;
 
 /**
  * Multichoice Question.
- *
- * @QuizQuestion (
- *   id = "multichoice",
- *   label = @Translation("Multiple choice question"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_multichoice\Plugin\quiz\QuizQuestion\MultichoiceResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'multichoice',
+  label: new TranslatableMarkup('Multiple choice question'),
+  handlers: ['response' => MultichoiceResponse::class],
+)]
 class MultichoiceQuestion extends QuizQuestion {
 
   use StringTranslationTrait;
diff --git a/modules/quiz_page/src/Plugin/quiz/QuizQuestion/QuizPageQuestion.php b/modules/quiz_page/src/Plugin/quiz/QuizQuestion/QuizPageQuestion.php
index abc49bc6167e39d3458719eb90b5b52d5bf6b06a..021a5ac0373547e6a93c9aec149c367f4d57dd3c 100644
--- a/modules/quiz_page/src/Plugin/quiz/QuizQuestion/QuizPageQuestion.php
+++ b/modules/quiz_page/src/Plugin/quiz/QuizQuestion/QuizPageQuestion.php
@@ -3,6 +3,8 @@
 namespace Drupal\quiz_page\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 
@@ -14,25 +16,21 @@ use Drupal\quiz\Entity\QuizResultAnswer;
  *
  * A Quiz page node is a placeholder for presenting multiple questions
  * on the same page.
- *
- * @QuizQuestion (
- *   id = "page",
- *   label = @Translation("Quiz page"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_page\Plugin\quiz\QuizQuestion\QuizPageResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'page',
+  label: new TranslatableMarkup('Quiz page'),
+  handlers: ['response' => QuizPageResponse::class],
+)]
 class QuizPageQuestion extends QuizQuestion {
 
   /**
    * {@inheritdoc}
    */
   public function getAnsweringForm(FormStateInterface $form_state, QuizResultAnswer $quizQuestionResultAnswer): array {
-    $element = [
+    return [
       '#type' => 'hidden',
     ];
-    return $element;
   }
 
   /**
@@ -40,7 +38,7 @@ class QuizPageQuestion extends QuizQuestion {
    *
    * @see QuizQuestion::getCreationForm()
    */
-  public function getCreationForm(array &$form_state = NULL) {
+  public function getCreationForm(array &$form_state = NULL): array {
     return [];
   }
 
diff --git a/modules/quiz_short_answer/src/Plugin/quiz/QuizQuestion/ShortAnswerQuestion.php b/modules/quiz_short_answer/src/Plugin/quiz/QuizQuestion/ShortAnswerQuestion.php
index 1cfc8b1f409392869a5095f3ea5e1a36da485b41..b4384041033ba935cc2e0d3c125c9af4a0d00301 100644
--- a/modules/quiz_short_answer/src/Plugin/quiz/QuizQuestion/ShortAnswerQuestion.php
+++ b/modules/quiz_short_answer/src/Plugin/quiz/QuizQuestion/ShortAnswerQuestion.php
@@ -4,20 +4,19 @@ namespace Drupal\quiz_short_answer\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 
 /**
  * Short answer question plugin.
- *
- * @QuizQuestion (
- *   id = "short_answer",
- *   label = @Translation("Short answer question"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_short_answer\Plugin\quiz\QuizQuestion\ShortAnswerResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'short_answer',
+  label: new TranslatableMarkup('Short answer question'),
+  handlers: ['response' => ShortAnswerResponse::class],
+)]
 class ShortAnswerQuestion extends QuizQuestion {
 
   use StringTranslationTrait;
diff --git a/modules/quiz_truefalse/src/Plugin/quiz/QuizQuestion/TrueFalseQuestion.php b/modules/quiz_truefalse/src/Plugin/quiz/QuizQuestion/TrueFalseQuestion.php
index 2ba7fd3b824a11d841da90a3f348f15692f3b6e5..0c784af33fb8322e49f3324cca5464bc507d36b3 100644
--- a/modules/quiz_truefalse/src/Plugin/quiz/QuizQuestion/TrueFalseQuestion.php
+++ b/modules/quiz_truefalse/src/Plugin/quiz/QuizQuestion/TrueFalseQuestion.php
@@ -4,20 +4,19 @@ namespace Drupal\quiz_truefalse\Plugin\quiz\QuizQuestion;
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\quiz\Attribute\QuizQuestion as QuizQuestionAttribute;
 use Drupal\quiz\Entity\QuizQuestion;
 use Drupal\quiz\Entity\QuizResultAnswer;
 
 /**
  * The true/false question plugin.
- *
- * @QuizQuestion (
- *   id = "truefalse",
- *   label = @Translation("True/false question"),
- *   handlers = {
- *     "response" = "\Drupal\quiz_truefalse\Plugin\quiz\QuizQuestion\TrueFalseResponse"
- *   }
- * )
  */
+#[QuizQuestionAttribute(
+  id: 'truefalse',
+  label: new TranslatableMarkup('True/false question'),
+  handlers: ['response' => TrueFalseResponse::class],
+)]
 class TrueFalseQuestion extends QuizQuestion {
 
   use StringTranslationTrait;
diff --git a/quiz.api.php b/quiz.api.php
index 450a8bb2ae9c6b85c6f8e15724395458817ac40a..ee41b509dbe17bd5cc08edca6ab35f038b68cce2 100644
--- a/quiz.api.php
+++ b/quiz.api.php
@@ -9,9 +9,6 @@ use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
- * @file quiz.api.php
- * Hooks provided by Quiz module.
- *
  * These entity types provided by Quiz also have entity API hooks. There are a
  * few additional Quiz specific hooks defined in this file.
  *
@@ -25,7 +22,8 @@ use Drupal\Core\Session\AccountInterface;
  *
  * hook_quiz_result_presave(QuizResult $quiz_result)
  *   - Runs before a result is saved to the DB.
- * hook_quiz_question_relationship_insert(QuizQuestionRelationship $quiz_question_relationship)
+ * hook_quiz_question_relationship_insert(
+ * QuizQuestionRelationship $quiz_question_relationship)
  *   - Runs when a new question is added to a quiz.
  *
  * You can also use Rules to build conditional actions based off of these
diff --git a/quiz.module b/quiz.module
index 8c5c7befb88e457aebf687c92db768994f8e2d71..d68ed0639f179f7997e295a9d77c4b717fc23925 100644
--- a/quiz.module
+++ b/quiz.module
@@ -519,9 +519,9 @@ function quiz_get_feedback_options(): array {
   $feedback_options = Drupal::moduleHandler()->invokeAll('quiz_feedback_options');
 
   $view_modes = Drupal::service('entity_display.repository')->getViewModes('quiz_question');
-  $feedback_options["quiz_question_view_full"] = t('Question' . ': ' . 'Full');
+  $feedback_options["quiz_question_view_full"] = t('Question: Full');
   foreach ($view_modes as $view_mode => $info) {
-    $feedback_options["quiz_question_view_" . $view_mode] = t('Question' . ': ' . $info['label']);
+    $feedback_options["quiz_question_view_" . $view_mode] = t('Question: @label', ['@label' => $info['label']]);
   }
 
   $feedback_options += [
diff --git a/quiz.rules_defaults.inc b/quiz.rules_defaults.inc
index 5d61297a1a8c5bacca924e676d903c52adfb7f56..e9f2ec7adb9eadc4e55d717d11bfe8d6af0b4932 100644
--- a/quiz.rules_defaults.inc
+++ b/quiz.rules_defaults.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Used for interaction with rules module
+ * Used for interaction with rules module.
  *
  * @todo not entirely sure?
  */
diff --git a/src/Attribute/QuizQuestion.php b/src/Attribute/QuizQuestion.php
new file mode 100644
index 0000000000000000000000000000000000000000..c3e58fbd287e9bb78086431495d246fa3191ce3b
--- /dev/null
+++ b/src/Attribute/QuizQuestion.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\quiz\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines a Plugin attribute class for quiz questions.
+ *
+ * @see QuizQuestionPluginManager
+ * @see plugin_api
+ *
+ * @ingroup quiz
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class QuizQuestion extends Plugin {
+
+  /**
+   * Constructs a QuizQuestion attribute.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $label
+   *   The label of the plugin.
+   * @param array $handlers
+   *   Array handlers for the question.
+   * @param class-string|null $deriver
+   *   (optional) The deriver class.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $label = NULL,
+    protected readonly array $handlers = [],
+    public readonly ?string $deriver = NULL,
+  ) {
+  }
+
+}
diff --git a/src/Entity/QuizFeedbackType.php b/src/Entity/QuizFeedbackType.php
index 77931b90718d401eca8ca1531736506ab94265fc..1e0039aec409925684a9e6e5c924974909126394 100644
--- a/src/Entity/QuizFeedbackType.php
+++ b/src/Entity/QuizFeedbackType.php
@@ -54,7 +54,7 @@ class QuizFeedbackType extends ConfigEntityBase implements RulesUiComponentProvi
   /**
    * {@inheritdoc}
    */
-  public function getComponent() {
+  public function getComponent(): RulesComponent {
     if (empty($this->component)) {
       // Provide a default for now.
       // @todo make expression configurable.
diff --git a/src/Entity/QuizQuestion.php b/src/Entity/QuizQuestion.php
index 62406362f84088eef11718988b8a0b21570a744c..9056f6a7a3efa11eb585381f33d17a8321a053ac 100644
--- a/src/Entity/QuizQuestion.php
+++ b/src/Entity/QuizQuestion.php
@@ -69,7 +69,7 @@ use Drupal\user\EntityOwnerTrait;
  *   }
  * )
  */
-abstract class QuizQuestion extends EditorialContentEntityBase implements QuizQuestionInterface, EntityOwnerInterface {
+class QuizQuestion extends EditorialContentEntityBase implements QuizQuestionInterface, EntityOwnerInterface {
 
   /**
    * Define question statuses...
@@ -141,4 +141,11 @@ abstract class QuizQuestion extends EditorialContentEntityBase implements QuizQu
     return parent::save();
   }
 
+  /**
+   * @return int
+   */
+  public function getMaximumScore(): int {
+    return 0;
+  }
+
 }
diff --git a/src/Entity/QuizQuestionBroken.php b/src/Entity/QuizQuestionBroken.php
index e3a8efed5f1171fae9c30e0b05f09dce83631295..dd73182b596d1426380e9208753d00cb7b4cc1d4 100644
--- a/src/Entity/QuizQuestionBroken.php
+++ b/src/Entity/QuizQuestionBroken.php
@@ -7,11 +7,4 @@ namespace Drupal\quiz\Entity;
  */
 class QuizQuestionBroken extends QuizQuestion {
 
-  /**
-   *
-   */
-  public function getMaximumScore(): int {
-    return 0;
-  }
-
 }
diff --git a/src/Entity/QuizResultAnswer.php b/src/Entity/QuizResultAnswer.php
index 27b7dded76f54bcf01eb74bc4b91afaa69dca9bb..34f75ead5b0d27875ffc2841efa14fa90a2e8f05 100644
--- a/src/Entity/QuizResultAnswer.php
+++ b/src/Entity/QuizResultAnswer.php
@@ -50,7 +50,7 @@ use Drupal\quiz\QuizAnswerInterface;
  *   }
  * )
  */
-abstract class QuizResultAnswer extends ContentEntityBase implements QuizAnswerInterface {
+class QuizResultAnswer extends ContentEntityBase implements QuizAnswerInterface {
 
   use QuizResultAnswerEntityTrait;
 
@@ -158,7 +158,7 @@ abstract class QuizResultAnswer extends ContentEntityBase implements QuizAnswerI
   /**
    * {@inheritdoc}
    *
-   * Quiz result answers are never viewed outside of a Quiz result, so we
+   * Quiz result answers are never viewed outside a Quiz result, so we
    * enforce that a Quiz result route parameter is added.
    */
   public function toUrl($rel = 'canonical', array $options = []) {
@@ -168,4 +168,18 @@ abstract class QuizResultAnswer extends ContentEntityBase implements QuizAnswerI
     return $url;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function score(array $values): ?int {
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getResponse() {
+    return NULL;
+  }
+
 }
diff --git a/src/Entity/QuizResultAnswerEntityTrait.php b/src/Entity/QuizResultAnswerEntityTrait.php
index 39574b411c860e5d7db8f0fd5e1c0017e9951d91..f61ae7123be3c32cb4e21238c6e1c0c6cfe38785 100644
--- a/src/Entity/QuizResultAnswerEntityTrait.php
+++ b/src/Entity/QuizResultAnswerEntityTrait.php
@@ -93,7 +93,6 @@ trait QuizResultAnswerEntityTrait {
     if ($quiz->get('randomization')->getString() == 3) {
       /** @var Drupal\paragraphs\Entity\Paragraph[] $terms */
       $terms = $quiz->get('quiz_terms')->referencedEntities();
-      $total_questions = [];
       foreach ($terms as $term) {
         if ($term->get('quiz_question_tid')->getString() == $this->get('tid')->getString()) {
           return $term->get('quiz_question_max_score')->getString();
diff --git a/src/Entity/QuizViewsData.php b/src/Entity/QuizViewsData.php
index d80c4bfd98201070fa6fde291fb172fcd425ab99..d1fb7337981df82db57a59670e32d777132719f2 100644
--- a/src/Entity/QuizViewsData.php
+++ b/src/Entity/QuizViewsData.php
@@ -17,7 +17,7 @@ class QuizViewsData extends EntityViewsData {
    *
    * @todo Cleanup once https://www.drupal.org/node/2489476 lands.
    */
-  public function getViewsData() {
+  public function getViewsData(): array {
     $data = parent::getViewsData();
 
     foreach (['quiz', 'quiz_revision'] as $table) {
diff --git a/src/Plugin/QuizQuestionPluginManager.php b/src/Plugin/QuizQuestionPluginManager.php
index aee2858dc0232340136e3150160cb60d5be03312..9a06c56b5dbbb1e64c38cad7fe8bc551b3861e93 100644
--- a/src/Plugin/QuizQuestionPluginManager.php
+++ b/src/Plugin/QuizQuestionPluginManager.php
@@ -5,8 +5,7 @@ namespace Drupal\quiz\Plugin;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
-use Drupal\quiz\Annotation\QuizQuestion;
-
+use Drupal\quiz\Attribute\QuizQuestion;
 /**
  * Provides the Quiz Question plugin manager.
  */
@@ -24,7 +23,7 @@ class QuizQuestionPluginManager extends DefaultPluginManager {
    *   The module handler to invoke the alter hook with.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/quiz', $namespaces, $module_handler, QuizQuestionInterface::class, QuizQuestion::class);
+    parent::__construct('Plugin/quiz', $namespaces, $module_handler, QuizQuestionInterface::class,  QuizQuestion::class, 'Drupal\quiz\Annotation\QuizQuestion');
 
     $this->alterInfo('quiz_question_info');
     $this->setCacheBackend($cache_backend, 'quiz_question_plugins');
diff --git a/src/Entity/QuizResultListBuilder.php b/src/QuizResultListBuilder.php
similarity index 86%
rename from src/Entity/QuizResultListBuilder.php
rename to src/QuizResultListBuilder.php
index 59993c6ce4fab626e09b0973e9ec055a58f09313..65be8cc2a64df772bb55eef7b22018b332951723 100644
--- a/src/Entity/QuizResultListBuilder.php
+++ b/src/QuizResultListBuilder.php
@@ -1,9 +1,10 @@
 <?php
 
-namespace Drupal\quiz\Entity;
+namespace Drupal\quiz;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\quiz\Entity\QuizResult;
 
 /**
  * Defines the list builder for quiz results.
@@ -13,7 +14,7 @@ class QuizResultListBuilder extends EntityListBuilder {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     $build = parent::render();
     $build['table']['#caption'] = t('Quiz results.');
     return $build;
@@ -22,7 +23,7 @@ class QuizResultListBuilder extends EntityListBuilder {
   /**
    * {@inheritdoc}
    */
-  public function buildHeader() {
+  public function buildHeader(): array {
     $header['quiz'] = $this->t('Quiz');
     $header['user'] = $this->t('User');
     return $header + parent::buildHeader();
diff --git a/tests/src/Functional/QuizEvaluationTest.php b/tests/src/Functional/QuizEvaluationTest.php
index 15c888095a9a0cf7cb67a18a62368950ac8f875b..0ee346217fdb17a92d3fdf2bc7f9210bad3fbb9e 100644
--- a/tests/src/Functional/QuizEvaluationTest.php
+++ b/tests/src/Functional/QuizEvaluationTest.php
@@ -24,7 +24,7 @@ class QuizEvaluationTest extends QuizTestBase {
   /**
    * Test that a quiz result is marked as evaluated.
    */
-  public function testQuizEvaluation() {
+  public function testQuizEvaluation(): void {
     $this->drupalLogin($this->admin);
 
     $quiz_node = $this->createQuiz();
diff --git a/tests/src/Functional/QuizTestBase.php b/tests/src/Functional/QuizTestBase.php
index cb428b1fae3e1ead430c0edaf18295cac70d85b7..3afd36ea5dea84bfb763a8252d644947bab69c69 100644
--- a/tests/src/Functional/QuizTestBase.php
+++ b/tests/src/Functional/QuizTestBase.php
@@ -114,7 +114,7 @@ abstract class QuizTestBase extends BrowserTestBase {
    * @return \Drupal\quiz\Entity\Quiz
    *   The newly created Quiz object.
    */
-  public function createQuiz($settings = []) {
+  public function createQuiz($settings = []): Quiz {
     $settings += [
       'title' => 'Quiz',
       'body' => 'Quiz description',
@@ -136,7 +136,7 @@ abstract class QuizTestBase extends BrowserTestBase {
    * @return \Drupal\quiz\Entity\QuizQuestion
    *   The newly created Quiz Question object.
    */
-  public function createQuestion($settings = []) {
+  public function createQuestion(array $settings = []): QuizQuestion {
     $question = QuizQuestion::create($settings);
     $question->save();
     return $question;