diff --git a/.gitignore b/.gitignore
index 248d183b..dbcd095a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ yarn-error.log
 /dist
 /node_modules
 /temp
+/.idea
diff --git a/README.md b/README.md
index f9fc00be..9e75173e 100644
--- a/README.md
+++ b/README.md
@@ -117,6 +117,7 @@ The package includes the following rules (none of which are enabled by default):
 | `rxjs-no-unsafe-takeuntil` | Disallows the application of operators after `takeUntil`. Operators placed after `takeUntil` can effect [subscription leaks](https://medium.com/@cartant/rxjs-avoiding-takeuntil-leaks-fb5182d047ef). | [See below](#rxjs-no-unsafe-takeuntil) |
 | `rxjs-no-unused-add` | Disallows the importation of patched observables or operators that are not used in the module. | None |
 | `rxjs-no-wholesale` | Disallows the wholesale importation of `rxjs` or `rxjs/Rx`. | None |
+| `rxjs-prefer-angular-takeuntil-before-subscribe` | Enforces the application of the `takeUntil` operator when calling of `subscribe` within an Angular component. | [See below](#rxjs-prefer-angular-takeuntil-before-subscribe) |
 | `rxjs-prefer-angular-async-pipe` | Disallows the calling of `subscribe` within an Angular component. | None |
 | `rxjs-prefer-observer` | Enforces the passing of observers to `subscribe` and `tap`. See [this RxJS issue](https://github.com/ReactiveX/rxjs/issues/4159). | [See below](#rxjs-prefer-observer) |
 | `rxjs-suffix-subjects` | Disalllows subjects that don't end with the specified `suffix` option. | [See below](#rxjs-suffix-subjects) |
@@ -395,6 +396,59 @@ The following options are equivalent to the rule's default configuration:
 }
 ```
 
+
+
+#### rxjs-prefer-angular-takeuntil-before-subscribe
+
+This rule tries to avoid memory leaks in angular components when calling `.subscribe()` without properly unsubscribing 
+by enforcing the application of the `takeUntil(this.destroy$)` operator before the `.subscribe()` 
+as well as before certain operators (`publish`, `publishBehavior`, `publishLast`, `publishReplay`, `shareReplay`)
+and ensuring the component implements the `ngOnDestroy` 
+method invoking `this.destroy$.next()` and `this.destroy$.complete()`.
+
+##### Example
+This should trigger an error:
+```typescript
+@Component({
+  selector: 'app-my',
+  template: '
{{k$ | async}}
'
+})
+class MyComponent {
+      ~~~~~~~~~~~    component containing subscribe must implement the ngOnDestroy() method
+
+    
+    k$ = a.pipe(shareReplay(1));
+                ~~~~~~~~~~~~~~   the shareReplay operator used within a component must be preceded by takeUntil
+
+    someMethod() {
+        const e = a.pipe(switchMap(_ => b)).subscribe();
+                                            ~~~~~~~~~      subscribe within a component must be preceded by takeUntil
+    }
+}
+```
+
+while this should be fine:
+```typescript
+@Component({
+  selector: 'app-my',
+  template: '{{k$ | async}}
'
+})
+class MyComponent implements SomeInterface, OnDestroy {
+    private destroy$: Subject = new Subject();
+
+    k$ = a.pipe(takeUntil(this.destroy$), shareReplay(1));
+
+    someMethod() {
+        const e = a.pipe(switchMap(_ => b), takeUntil(this.destroy$)).subscribe();
+    }
+
+    ngOnDestroy() {
+      this.destroy$.next();
+      this.destroy$.complete();
+    }
+}
+```
+
 
 
 #### rxjs-prefer-observer
diff --git a/docs/index.md b/docs/index.md
index b4931bfd..4b0c31a1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -53,6 +53,7 @@ The package includes the following rules (none of which are enabled by default):
 | `rxjs-no-unsafe-takeuntil` | Disallows the application of operators after `takeUntil`. Operators placed after `takeUntil` can effect [subscription leaks](https://medium.com/@cartant/rxjs-avoiding-takeuntil-leaks-fb5182d047ef). | [See below](#rxjs-no-unsafe-takeuntil) |
 | `rxjs-no-unused-add` | Disallows the importation of patched observables or operators that are not used in the module. | None |
 | `rxjs-no-wholesale` | Disallows the wholesale importation of `rxjs` or `rxjs/Rx`. | None |
+| `rxjs-prefer-angular-takeuntil-before-subscribe` | Enforces the application of the `takeUntil` operator when calling of `subscribe` within an Angular component. | [See below](#rxjs-prefer-angular-takeuntil-before-subscribe) |
 | `rxjs-prefer-angular-async-pipe` | Disallows the calling of `subscribe` within an Angular component. | None |
 | `rxjs-prefer-observer` | Enforces the passing of observers to `subscribe` and `tap`. See [this RxJS issue](https://github.com/ReactiveX/rxjs/issues/4159). | [See below](#rxjs-prefer-observer) |
 | `rxjs-suffix-subjects` | Disalllows subjects that don't end with the specified `suffix` option. | [See below](#rxjs-suffix-subjects) |
@@ -331,6 +332,62 @@ The following options are equivalent to the rule's default configuration:
 }
 ```
 
+
+
+
+
+
+#### rxjs-prefer-angular-takeuntil-before-subscribe
+
+This rule tries to avoid memory leaks in angular components when calling `.subscribe()` without properly unsubscribing 
+by enforcing the application of the `takeUntil(this.destroy$)` operator before the `.subscribe()` 
+as well as before certain operators (`publish`, `publishBehavior`, `publishLast`, `publishReplay`, `shareReplay`)
+and ensuring the component implements the `ngOnDestroy` 
+method invoking `this.destroy$.next()` and `this.destroy$.complete()`.
+
+##### Example
+This should trigger an error:
+```typescript
+@Component({
+  selector: 'app-my',
+  template: '{{k$ | async}}
'
+})
+class MyComponent {
+      ~~~~~~~~~~~    component containing subscribe must implement the ngOnDestroy() method
+
+    
+    k$ = a.pipe(shareReplay(1));
+                ~~~~~~~~~~~~~~   the shareReplay operator used within a component must be preceded by takeUntil
+
+    someMethod() {
+        const e = a.pipe(switchMap(_ => b)).subscribe();
+                                            ~~~~~~~~~      subscribe within a component must be preceded by takeUntil
+    }
+}
+```
+
+while this should be fine:
+```typescript
+@Component({
+  selector: 'app-my',
+  template: '{{k$ | async}}
'
+})
+class MyComponent implements SomeInterface, OnDestroy {
+    private destroy$: Subject = new Subject();
+
+    k$ = a.pipe(takeUntil(this.destroy$), shareReplay(1));
+
+    someMethod() {
+        const e = a.pipe(switchMap(_ => b), takeUntil(this.destroy$)).subscribe();
+    }
+
+    ngOnDestroy() {
+      this.destroy$.next();
+      this.destroy$.complete();
+    }
+}
+```
+
 
 
 #### rxjs-prefer-observer
diff --git a/source/rules/rxjsPreferAngularTakeuntilBeforeSubscribeRule.ts b/source/rules/rxjsPreferAngularTakeuntilBeforeSubscribeRule.ts
new file mode 100644
index 00000000..19c90641
--- /dev/null
+++ b/source/rules/rxjsPreferAngularTakeuntilBeforeSubscribeRule.ts
@@ -0,0 +1,438 @@
+/**
+ * @license Use of this source code is governed by an MIT-style license that
+ * can be found in the LICENSE file at https://github.com/cartant/rxjs-tslint-rules
+ */
+/*tslint:disable:no-use-before-declare*/
+
+import * as Lint from "tslint";
+import * as tsutils from "tsutils";
+import * as ts from "typescript";
+import { couldBeType } from "../support/util";
+import { tsquery } from "@phenomnomnominal/tsquery";
+import { dedent } from "tslint/lib/utils";
+
+export class Rule extends Lint.Rules.TypedRule {
+  public static metadata: Lint.IRuleMetadata = {
+    description: dedent`Enforces the application of the takeUntil operator
+                        when calling of subscribe within an Angular component.`,
+    options: null,
+    optionsDescription: "",
+    requiresTypeInfo: true,
+    ruleName: "rxjs-prefer-angular-takeuntil-before-subscribe",
+    type: "functionality",
+    typescriptOnly: true
+  };
+
+  public static FAILURE_STRING =
+    "subscribe within a component must be preceded by takeUntil";
+
+  public static FAILURE_STRING_SUBJECT_NAME =
+    "takeUntil argument must be a property of the class, e.g. takeUntil(this.destroy$)";
+
+  public static FAILURE_STRING_OPERATOR =
+    "the {operator} operator used within a component must be preceded by takeUntil";
+
+  public static FAILURE_STRING_NG_ON_DESTROY =
+    "component containing subscribe must implement the ngOnDestroy() method";
+
+  public static FAILURE_STRING_NG_ON_DESTROY_SUBJECT_METHOD_NOT_CALLED =
+    "there must be an invocation of {destroySubjectName}.{methodName}() in ngOnDestroy()";
+
+  private operatorsRequiringPrecedingTakeuntil: string[] = [
+    "publish",
+    "publishBehavior",
+    "publishLast",
+    "publishReplay",
+    "shareReplay"
+  ];
+
+  public applyWithProgram(
+    sourceFile: ts.SourceFile,
+    program: ts.Program
+  ): Lint.RuleFailure[] {
+    const failures: Lint.RuleFailure[] = [];
+
+    // find all classes with an @Component() decorator
+    const componentClassDeclarations = tsquery(
+      sourceFile,
+      `ClassDeclaration:has(Decorator[expression.expression.name='Component'])`
+    );
+    componentClassDeclarations.forEach(componentClassDeclaration => {
+      failures.push(
+        ...this.checkComponentClassDeclaration(
+          sourceFile,
+          program,
+          componentClassDeclaration as ts.ClassDeclaration
+        )
+      );
+    });
+
+    return failures;
+  }
+
+  /**
+   * Checks a component class for occurrences of .subscribe() and corresponding takeUntil() requirements
+   */
+  private checkComponentClassDeclaration(
+    sourceFile: ts.SourceFile,
+    program: ts.Program,
+    componentClassDeclaration: ts.ClassDeclaration
+  ): Lint.RuleFailure[] {
+    const failures: Lint.RuleFailure[] = [];
+
+    const typeChecker = program.getTypeChecker();
+    /** list of destroy subjects used in takeUntil() operators */
+    const destroySubjectNamesUsed: {
+      [destroySubjectName: string]: boolean;
+    } = {};
+
+    // find observable.subscribe() call expressions
+    const subscribePropertyAccessExpressions = tsquery(
+      componentClassDeclaration,
+      `CallExpression > PropertyAccessExpression[name.name="subscribe"]`
+    );
+
+    // check whether it is an observable and check the takeUntil before the subscribe
+    subscribePropertyAccessExpressions.forEach(node => {
+      const propertyAccessExpression = node as ts.PropertyAccessExpression;
+      const type = typeChecker.getTypeAtLocation(
+        propertyAccessExpression.expression
+      );
+      if (couldBeType(type, "Observable")) {
+        const subscribeFailures = this.checkTakeuntilBeforeSubscribe(
+          sourceFile,
+          propertyAccessExpression
+        );
+        failures.push(...subscribeFailures.failures);
+        if (subscribeFailures.destroySubjectName) {
+          destroySubjectNamesUsed[subscribeFailures.destroySubjectName] = true;
+        }
+      }
+    });
+
+    // find observable.pipe() call expressions
+    const pipePropertyAccessExpressions = tsquery(
+      componentClassDeclaration,
+      `CallExpression > PropertyAccessExpression[name.name="pipe"]`
+    );
+
+    // check whether it is an observable and check the takeUntil before operators requiring it
+    pipePropertyAccessExpressions.forEach(node => {
+      const propertyAccessExpression = node as ts.PropertyAccessExpression;
+      const pipeCallExpression = node.parent as ts.CallExpression;
+      const type = typeChecker.getTypeAtLocation(
+        propertyAccessExpression.expression
+      );
+      if (couldBeType(type, "Observable")) {
+        const pipeFailures = this.checkTakeuntilBeforeOperatorsInPipe(
+          sourceFile,
+          pipeCallExpression.arguments
+        );
+        failures.push(...pipeFailures.failures);
+        pipeFailures.destroySubjectNames.forEach(destroySubjectName => {
+          if (destroySubjectName) {
+            destroySubjectNamesUsed[destroySubjectName] = true;
+          }
+        });
+      }
+    });
+
+    // check the ngOnDestroyMethod
+    const destroySubjectNamesUsedList = Object.keys(destroySubjectNamesUsed);
+    if (destroySubjectNamesUsedList.length > 0) {
+      const ngOnDestroyFailures = this.checkNgOnDestroy(
+        sourceFile,
+        componentClassDeclaration as ts.ClassDeclaration,
+        destroySubjectNamesUsedList
+      );
+      failures.push(...ngOnDestroyFailures);
+    }
+
+    return failures;
+  }
+
+  /**
+   * Checks whether a .subscribe() is preceded by a .pipe(<...>, takeUntil(<...>))
+   */
+  private checkTakeuntilBeforeSubscribe(
+    sourceFile: ts.SourceFile,
+    node: ts.PropertyAccessExpression
+  ): { failures: Lint.RuleFailure[]; destroySubjectName: string } {
+    const failures: Lint.RuleFailure[] = [];
+    const subscribeContext = node.expression;
+
+    /** Whether a takeUntil() operator preceding the .subscribe() was found */
+    let lastTakeUntilFound = false;
+    /** name of the takeUntil() argument */
+    let destroySubjectName: string;
+
+    // check whether subscribeContext.expression is .pipe()
+    if (
+      tsutils.isCallExpression(subscribeContext) &&
+      tsutils.isPropertyAccessExpression(subscribeContext.expression) &&
+      subscribeContext.expression.name.getText() === "pipe"
+    ) {
+      const pipedOperators = subscribeContext.arguments;
+      if (pipedOperators.length > 0) {
+        const lastPipedOperator = pipedOperators[pipedOperators.length - 1];
+        // check whether the last operator in the .pipe() call is takeUntil()
+        if (tsutils.isCallExpression(lastPipedOperator)) {
+          const lastPipedOperatorFailures = this.checkTakeuntilOperator(
+            sourceFile,
+            lastPipedOperator
+          );
+          if (lastPipedOperatorFailures.isTakeUntil) {
+            lastTakeUntilFound = true;
+            destroySubjectName = lastPipedOperatorFailures.destroySubjectName;
+            failures.push(...lastPipedOperatorFailures.failures);
+          }
+        }
+      }
+    }
+
+    // add failure if there is no takeUntil() in the last position of a .pipe()
+    if (!lastTakeUntilFound) {
+      failures.push(
+        new Lint.RuleFailure(
+          sourceFile,
+          node.name.getStart(),
+          node.name.getStart() + node.name.getWidth(),
+          Rule.FAILURE_STRING,
+          this.ruleName
+        )
+      );
+    }
+
+    return { failures, destroySubjectName: destroySubjectName };
+  }
+
+  /**
+   * Checks whether there is a takeUntil() operator before operators like shareReplay()
+   */
+  private checkTakeuntilBeforeOperatorsInPipe(
+    sourceFile: ts.SourceFile,
+    pipeArguments: ts.NodeArray
+  ): { failures: Lint.RuleFailure[]; destroySubjectNames: string[] } {
+    const failures: Lint.RuleFailure[] = [];
+    const destroySubjectNames: string[] = [];
+
+    // go though all pipe arguments, i.e. rxjs operators
+    pipeArguments.forEach((pipeArgument, i) => {
+      // check whether the operator requires a preceding takeuntil
+      if (
+        tsutils.isCallExpression(pipeArgument) &&
+        tsutils.isIdentifier(pipeArgument.expression) &&
+        this.operatorsRequiringPrecedingTakeuntil.includes(
+          pipeArgument.expression.getText()
+        )
+      ) {
+        let precedingTakeUntilOperatorFound = false;
+        // check the preceding operator to be takeuntil
+        if (
+          i > 0 &&
+          pipeArguments[i - 1] &&
+          tsutils.isCallExpression(pipeArguments[i - 1])
+        ) {
+          const precedingOperator = pipeArguments[i - 1] as ts.CallExpression;
+          const precedingOperatorFailures = this.checkTakeuntilOperator(
+            sourceFile,
+            precedingOperator
+          );
+          if (precedingOperatorFailures.isTakeUntil) {
+            precedingTakeUntilOperatorFound = true;
+            failures.push(...precedingOperatorFailures.failures);
+            if (precedingOperatorFailures.destroySubjectName) {
+              destroySubjectNames.push(
+                precedingOperatorFailures.destroySubjectName
+              );
+            }
+          }
+        }
+
+        if (!precedingTakeUntilOperatorFound) {
+          failures.push(
+            new Lint.RuleFailure(
+              sourceFile,
+              pipeArgument.getStart(),
+              pipeArgument.getStart() + pipeArgument.getWidth(),
+              Rule.FAILURE_STRING_OPERATOR.replace(
+                "{operator}",
+                pipeArgument.expression.getText()
+              ),
+              this.ruleName
+            )
+          );
+        }
+      }
+    });
+
+    return { failures, destroySubjectNames: destroySubjectNames };
+  }
+
+  /**
+   * Checks whether the operator given is takeUntil and uses an allowed destroy subject name
+   */
+  private checkTakeuntilOperator(
+    sourceFile: ts.SourceFile,
+    operator: ts.CallExpression
+  ): {
+    failures: Lint.RuleFailure[];
+    destroySubjectName: string;
+    isTakeUntil: boolean;
+  } {
+    const failures: Lint.RuleFailure[] = [];
+    let destroySubjectName: string;
+    let isTakeUntil: boolean = false;
+
+    if (
+      tsutils.isIdentifier(operator.expression) &&
+      operator.expression.text === "takeUntil"
+    ) {
+      isTakeUntil = true;
+      // check the argument of takeUntil()
+      const destroySubjectNameCheck = this.checkDestroySubjectName(
+        sourceFile,
+        operator
+      );
+      failures.push(...destroySubjectNameCheck.failures);
+      destroySubjectName = destroySubjectNameCheck.destroySubjectName;
+    }
+
+    return { failures, destroySubjectName, isTakeUntil };
+  }
+
+  /**
+   * Checks whether the argument of the given takeUntil(this.destroy$) expression
+   * is a property of the class
+   */
+  private checkDestroySubjectName(
+    sourceFile: ts.SourceFile,
+    takeUntilOperator: ts.CallExpression
+  ): { failures: Lint.RuleFailure[]; destroySubjectName: string } {
+    const failures: Lint.RuleFailure[] = [];
+
+    /** name of the takeUntil() argument */
+    let destroySubjectName: string;
+
+    /** whether the takeUntil() argument is among the allowed names */
+    let isAllowedDestroySubject = false;
+
+    let takeUntilOperatorArgument: ts.PropertyAccessExpression;
+    let highlightedNode: ts.Expression = takeUntilOperator;
+
+    // check the takeUntil() argument
+    if (
+      takeUntilOperator.arguments.length >= 1 &&
+      takeUntilOperator.arguments[0]
+    ) {
+      highlightedNode = takeUntilOperator.arguments[0];
+      if (tsutils.isPropertyAccessExpression(takeUntilOperator.arguments[0])) {
+        takeUntilOperatorArgument = takeUntilOperator
+          .arguments[0] as ts.PropertyAccessExpression;
+        destroySubjectName = takeUntilOperatorArgument.name.getText();
+        isAllowedDestroySubject = true;
+      }
+    }
+
+    if (!isAllowedDestroySubject) {
+      failures.push(
+        new Lint.RuleFailure(
+          sourceFile,
+          highlightedNode.getStart(),
+          highlightedNode.getStart() + highlightedNode.getWidth(),
+          Rule.FAILURE_STRING_SUBJECT_NAME,
+          this.ruleName
+        )
+      );
+    }
+
+    return { failures, destroySubjectName };
+  }
+
+  /**
+   * Checks whether the class implements an ngOnDestroy method and invokes .next() and .complete() on the destroy subjects
+   */
+  private checkNgOnDestroy(
+    sourceFile: ts.SourceFile,
+    classDeclaration: ts.ClassDeclaration,
+    destroySubjectNamesUsed: string[]
+  ): Lint.RuleFailure[] {
+    const failures: Lint.RuleFailure[] = [];
+    const ngOnDestroyMethod = classDeclaration.members.find(
+      member => member.name && member.name.getText() === "ngOnDestroy"
+    );
+
+    // check whether the ngOnDestroy method is implemented
+    // and contains invocations of .next() and .complete() on all destroy subjects used
+    if (ngOnDestroyMethod) {
+      failures.push(
+        ...this.checkDestroySubjectMethodInvocation(
+          sourceFile,
+          ngOnDestroyMethod,
+          destroySubjectNamesUsed,
+          "next"
+        )
+      );
+      failures.push(
+        ...this.checkDestroySubjectMethodInvocation(
+          sourceFile,
+          ngOnDestroyMethod,
+          destroySubjectNamesUsed,
+          "complete"
+        )
+      );
+    } else {
+      failures.push(
+        new Lint.RuleFailure(
+          sourceFile,
+          classDeclaration.name.getStart(),
+          classDeclaration.name.getStart() + classDeclaration.name.getWidth(),
+          Rule.FAILURE_STRING_NG_ON_DESTROY,
+          this.ruleName
+        )
+      );
+    }
+    return failures;
+  }
+
+  /**
+   * Checks whether all .() are invoked in the ngOnDestroyMethod
+   */
+  private checkDestroySubjectMethodInvocation(
+    sourceFile: ts.SourceFile,
+    ngOnDestroyMethod: ts.ClassElement,
+    destroySubjectNamesUsed: string[],
+    methodName: string
+  ) {
+    const failures: Lint.RuleFailure[] = [];
+    const destroySubjectMethodInvocations = tsquery(
+      ngOnDestroyMethod,
+      `CallExpression > PropertyAccessExpression[name.name="${methodName}"]`
+    ) as ts.PropertyAccessExpression[];
+    destroySubjectNamesUsed.forEach(destroySubjectName => {
+      // check whether there is one invocation of .()
+      if (
+        !destroySubjectMethodInvocations.some(
+          nextInvocation =>
+            tsutils.isPropertyAccessExpression(nextInvocation.expression) &&
+            nextInvocation.expression.name.getText() === destroySubjectName
+        )
+      ) {
+        failures.push(
+          new Lint.RuleFailure(
+            sourceFile,
+            ngOnDestroyMethod.name.getStart(),
+            ngOnDestroyMethod.name.getStart() +
+              ngOnDestroyMethod.name.getWidth(),
+            Rule.FAILURE_STRING_NG_ON_DESTROY_SUBJECT_METHOD_NOT_CALLED.replace(
+              "{destroySubjectName}",
+              `this.${destroySubjectName}`
+            ).replace("{methodName}", methodName),
+            this.ruleName
+          )
+        );
+      }
+    });
+    return failures;
+  }
+}
diff --git a/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/fixture.ts.lint b/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/fixture.ts.lint
new file mode 100644
index 00000000..e0a16198
--- /dev/null
+++ b/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/fixture.ts.lint
@@ -0,0 +1,109 @@
+import { combineLatest, of, Subject } from "rxjs";
+import { switchMap, takeUntil, shareReplay, tap } from "rxjs/operators";
+
+const a = of("a");
+const b = of("b");
+const c = of("c");
+const d = of("d");
+
+const e = a.pipe(switchMap(_ => b)).subscribe();
+
+const f = a.pipe(switchMap(_ => b), takeUntil(d)).subscribe();
+
+const g = a.pipe(takeUntil(d), s => switchMap(_ => b)).subscribe();
+
+class MyClass {
+    someMethod() {
+        const e = a.pipe(switchMap(_ => b)).subscribe();
+
+        const f = a.pipe(switchMap(_ => b), takeUntil(d)).subscribe();
+
+        const g = a.pipe(takeUntil(d), s => switchMap(_ => b)).subscribe();
+    }
+}
+
+@Component({
+  selector: 'app-my'
+})
+class MyComponent {
+      ~~~~~~~~~~~                               [enforce-takeuntil-before-subscribe-ondestroy]
+
+    private destroy$: Subject = new Subject();
+
+    k$ = a.pipe(shareReplay(1));
+                ~~~~~~~~~~~~~~            [enforce-takeuntil-before-operator-sharereplay]
+
+    someMethod() {
+        const d = a.subscribe();
+                    ~~~~~~~~~                               [enforce-takeuntil-before-subscribe]
+
+        const e = a.pipe(switchMap(_ => b)).subscribe();
+                                            ~~~~~~~~~                               [enforce-takeuntil-before-subscribe]
+
+        const f = a.pipe(switchMap(_ => b), takeUntil(this.destroy$)).subscribe();
+
+        const g = a.pipe(takeUntil(this.destroy$), switchMap(_ => b)).subscribe();
+                                                                      ~~~~~~~~~            [enforce-takeuntil-before-subscribe]
+
+        const h = a.pipe(switchMap(_ => b), takeUntil(d)).subscribe();
+                                                      ~            [enforce-takeuntil-before-subscribe-subject-name]
+
+        const k1 = a.pipe(takeUntil(this.destroy$), shareReplay(1)).subscribe();
+                                                                    ~~~~~~~~~            [enforce-takeuntil-before-subscribe]
+
+        const k = a.pipe(shareReplay(1), takeUntil(this.destroy$)).subscribe();
+                         ~~~~~~~~~~~~~~            [enforce-takeuntil-before-operator-sharereplay]
+
+        const m = a.pipe(tap(), shareReplay(1), takeUntil(this.destroy$)).subscribe();
+                                ~~~~~~~~~~~~~~            [enforce-takeuntil-before-operator-sharereplay]
+
+        const n = a.pipe(takeUntil(d), shareReplay(1), takeUntil(this.destroy$)).subscribe();
+                                   ~            [enforce-takeuntil-before-subscribe-subject-name]
+
+    }
+}
+
+@Component({
+  selector: 'app-my'
+})
+class MyComponent implements OnDestroy {
+    someMethod() {
+        const f = a.pipe(switchMap(_ => b), takeUntil(this._destroy$)).subscribe();
+    }
+
+    ngOnDestroy() {
+    ~~~~~~~~~~~            [enforce-takeuntil-before-subscribe-next-missing]
+    ~~~~~~~~~~~            [enforce-takeuntil-before-subscribe-complete-missing]
+      // this._destroy$.next() is missing
+      this.destroy$.next();
+      this.destroy$.complete();
+    }
+}
+
+@Component({
+  selector: 'app-my'
+})
+class MyComponent implements SomeInterface, OnDestroy {
+    private destroy$: Subject = new Subject();
+
+    k$ = a.pipe(takeUntil(this.destroy$), shareReplay(1));
+
+    someMethod() {
+        const e = a.pipe(switchMap(_ => b), takeUntil(this.destroy$)).subscribe();
+
+        const k = a.pipe(takeUntil(this.destroy$), shareReplay(1), takeUntil(this.destroy$)).subscribe();
+    }
+
+    ngOnDestroy() {
+      this.destroy$.next();
+      this.destroy$.complete();
+    }
+}
+
+
+[enforce-takeuntil-before-subscribe]: subscribe within a component must be preceded by takeUntil
+[enforce-takeuntil-before-subscribe-subject-name]: takeUntil argument must be a property of the class, e.g. takeUntil(this.destroy$)
+[enforce-takeuntil-before-subscribe-ondestroy]: component containing subscribe must implement the ngOnDestroy() method
+[enforce-takeuntil-before-subscribe-next-missing]: there must be an invocation of this._destroy$.next() in ngOnDestroy()
+[enforce-takeuntil-before-subscribe-complete-missing]: there must be an invocation of this._destroy$.complete() in ngOnDestroy()
+[enforce-takeuntil-before-operator-sharereplay]: the shareReplay operator used within a component must be preceded by takeUntil
diff --git a/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/tsconfig.json b/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/tsconfig.json
new file mode 100644
index 00000000..690be78e
--- /dev/null
+++ b/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/tsconfig.json
@@ -0,0 +1,13 @@
+{
+  "compilerOptions": {
+    "baseUrl": ".",
+    "lib": ["es2015"],
+    "noEmit": true,
+    "paths": {
+      "rxjs": ["../../node_modules/rxjs"]
+    },
+    "skipLibCheck": true,
+    "target": "es5"
+  },
+  "include": ["fixture.ts"]
+}
diff --git a/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/tslint.json b/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/tslint.json
new file mode 100644
index 00000000..a2160ab8
--- /dev/null
+++ b/test/v6/fixtures/prefer-angular-takeuntil-before-subscribe/default/tslint.json
@@ -0,0 +1,8 @@
+{
+  "defaultSeverity": "error",
+  "jsRules": {},
+  "rules": {
+    "rxjs-prefer-angular-takeuntil-before-subscribe": { "severity": "error" }
+  },
+  "rulesDirectory": "../../../../../build/rules"
+}