Can a Jira sub-task sit directly under an epic? Yes — and only in company-managed projects
Gabriela Perdum
Author
13 min readAugust 25, 2026
Key takeaways
In a company-managed project a sub-task can have an epic as its parent. Both the REST API and the Jira UI will do it, and neither warns you.
In a team-managed project the identical call is refused. I reproduced the refusal on two separate team-managed projects with passing controls in each.
Atlassian documents this as expected behaviour and lists five ways it happens. A widely accepted community answer says it is impossible. The community answer is the one that is wrong.
Once it exists, parent and parentEpic see it, but Epic Link and the Agile epic endpoint do not — so half your reports quietly disagree with the other half.
Find them with hierarchyLevel = -1 AND parent in (<your epic keys>). Do not use parent in subTaskIssueTypes(): it runs, returns rows, and every row is a false positive.
On 3 July a member asked the Atlassian Community how to skip a level of hierarchy in a parent-child relationship. They had four levels — Initiative, Feature, Epic, Story — and wanted some work to hang Epic straight off Initiative, skipping Feature. I answered that thread. I said native parent-child cannot skip a level, that the hierarchy is a single ordered stack and the parent field only reaches the level immediately above.
That answer is right everywhere I have been able to test it, except in one place. The exception is the sub-task level, it is not an edge case, and it is the one that quietly ruins reports — because when it happens, nothing in Jira tells you it happened.
So I stopped arguing about it and ran it on a live Cloud site. Everything below was measured on 2026-08-25 against a Jira Cloud site on the Free plan, in a company-managed software project created fresh for the probe and in two separate team-managed projects. Every ticket status and doc quote was re-read from the primary source the same day.
The rule as Atlassian states it
Jira ships three hierarchy levels. The work type hierarchy documentation puts it plainly: "By default, Jira is set up with three levels of work type hierarchy: a level for larger pieces of work (level 1, by default called Epic), a level for standard work items (level 0, called Story), and a level for smaller pieces of work (level -1, called Subtask)."
The consecutive-levels rule is stated most clearly not in a doc but in a feature request. JRACLOUD-89913, "Should have the ability to skip custom issue-type hierarchy", opens with: "Currently, when we define the custom hierarchy, the parent-child relation can be configured between consecutive issue-type levels." When I read that ticket on 2026-08-25 it was Gathering Interest, unresolved, with 80 votes and 50 watchers, created on 2023-08-03. Three years of people asking for the thing the member on that July thread wanted, and no.
So the rule is real, and my controls below confirm it holds for every standard level this site has. What it does not cover is the level below zero.
The claim everybody repeats
Search for this and you will land on an accepted answer that says it cannot be done. A widely repeated one sits on a thread titled Unable to see Sub-Tasks anymore on my Jira Stories, from a Rising Star, accepted, 9 kudos: "Subtasks can only be added to level 0 work item types. Subtasks cannot pass a level."
The fix in that answer is correct and the original poster confirmed it worked — their Story type had been moved from level 0 to level 3, and putting it back restored sub-task creation. It is only the stated mechanism that is wrong, and that is the ordinary way we all inherit someone else's model along with their good advice. I have repeated versions of that sentence myself.
Atlassian's own knowledge base says the opposite. The article Jira Epic issues have subtasks under them along with child issues carries a Cloud-only platform notice and was last updated 2025-09-26. Its Summary: "When opening an Epic issue, we see the option to 'Create child issues' and no option to 'Create Subtasks'. However, it is possible that Epic issue contains both child issues and subtasks under the Epic." Its Solution, verbatim:
This is expected behaviour in Jira. It is possible to create subtasks under all issue types above Subtask issue type in Jira Cloud.
The same article lists five routes in, and they are worth reading as a list of things that happen in real instances rather than as a curiosity:
"When the issue type was previously at a lower issue hierarchy level than Epic and a subtask was created under it. Then the button is always visible on the issue."
"When the issue type is at a higher level than Epic, however, a CSV import was performed, and a subtask issue was imported under this issue type."
"When the issue type is at a higher level than Epic and the subtask was created via the Jira issue navigator in the UI."
"It is possible to reparent a subtask from a Story/Task to an Epic/initiative via the Jira Cloud UI."
"An issuetype change was performed on a child issue under an Epic or higher issuetype such that the issue was changed from standard task to subtask."
An accepted community answer and an Atlassian knowledge base article, flatly contradicting each other about whether a thing is possible. That is a question you settle by running it.
What I measured: the company-managed project
I created a company-managed software project from the Scrum template, with the default types — Epic (id 10000, level 1), Story (10013, level 0), Task (10005, level 0), Sub-task (10016, level -1) — and posted issues at it.
An acceptance on its own proves nothing. A 201 is equally consistent with "Jira allows this" and with "this endpoint validates nothing at all", so the acceptance is only evidence if refusals in the same class, on the same object types, in the same run, prove the validator is awake. Here is the whole create-path run, refusals included:
POST /rest/api/3/issue
Result
Sub-task, parent = Epic
201 Created
Story, parent = Sub-task
400 — Parent issue ID: '22760' / Key: 'HIERP-3' can not be sub-task.
Story, parent = Story (same level)
400 — Please select valid parent issue.
Epic, parent = Story (inverted)
400 — Please select valid parent issue.
Task, parent = Sub-task
400 — Parent issue ID: '22760' / Key: 'HIERP-3' can not be sub-task.
Sub-task, parent = Sub-task
400 — Parent issue ID: '22760' / Key: 'HIERP-3' can not be sub-task.
Epic, parent = Epic
400 — Please select valid parent issue.
Sub-task, parent = an Epic in a different project
400 — Issues with this Issue Type must be created in the same project as the parent.
9 rows × 2 columnsHeader row enabled
Seven refusals and one acceptance. The validator is very much awake: it blocks same-level parents, inverted parents, sub-tasks as parents and cross-project parents. It does not block a sub-task from being parented two levels up, to an epic.
The body that produces it is unremarkable, which is the point:
Read it back and the relationship is entirely real. The sub-task's parent is the epic. The epic's own subtasks array lists it. parent = HIERP-1 in JQL returns it alongside the epic's ordinary story children.
The edit path behaves the same way. PUT /rest/api/3/issue/{key} with {"fields":{"parent":{"key":"<epic>"}}} on an existing sub-task returned 204 and stuck. The same controls held on the edit path too — a story onto a story, a story onto a sub-task, an epic onto a story and a sub-task onto a sub-task were all refused with 400, while the legal move (a story onto the epic) returned 204.
One thing to know before you debug someone else's failure here: every edit-path refusal comes back with the same wrong message. In-project or not, the PUT returns {"pid": "Issues with this Issue Type must be created in the same project as the parent."}. When I genuinely did use a parent in another project, that message was correct. When I moved a story onto a story inside one project, it was not. If a colleague sends you that error, do not go looking for a cross-project mistake first.
The UI blocks one door and holds the other one open
This is where I had to correct myself mid-run, which is the useful part.
There is a bug ticket in the neighbourhood that is worth reading before you assume Atlassian has this covered. JRACLOUD-89886 — "'Create sub-task' option is visible on some Jira tickets of Epic and above issuetype hierarchy" — was Closed as Fixed on 2025-07-22 (5 votes, 14 watchers, created 2024-07-08; the older key JSWCLOUD-26929 now redirects to it, which is worth knowing because a redirect is exactly what hides a status flip from you). Its Expected Results asked for two distinct things: "Hide/remove the 'Create sub-task' button from the issue view when the issue type is configured above an Epic in the Issue type hierarchy and prevent users from creating subtasks in such issue types".
That ticket is about work types configured above Epic, so it is adjacent to my case rather than identical to it, and I make no claim about which code shipped. What I can tell you is what a plain Epic does today. On my epic, Create child offers exactly four work types — Task, Story, Bug and Work package. No sub-task type appears, so you cannot create one from that menu.
The other route is wide open, and it is not hidden behind an API. Open any sub-task, click the parent in the breadcrumb, choose View all parents, and type the epic's name into the Change parent dialog. The epic is offered:
A sub-task's Change parent dialog in a company-managed project. HIERP-1 is an epic.
I clicked it and pressed Done. The write landed: the sub-task's Parent field now reads the epic, and the issue history records IssueParentAssociation HIERP-2 → HIERP-1. No warning, no confirmation, no mention of hierarchy anywhere in the flow. That matches route 4 in Atlassian's own list and it takes three clicks.
My first pass at this test got it backwards, and the reason is worth stealing. I ran the picker on a sub-task that was already parented to the epic, saw only stories offered, and nearly wrote "the UI filters epics out". It does not — the picker excludes the item's current parent, and the current parent happened to be the epic. Re-running it on a clean sub-task under a story is what produced the screenshot above. If a UI list "proves" a negative for you, check that the thing you expected to see is not being excluded for some entirely different reason. Atlassian's KB claiming the opposite of my first reading is what made me go back and look.
A UI that quietly disagrees with its own API is not new territory in Jira Cloud. The default value trap is the same shape pointing the other way: the admin UI removes the "None" option from a select field and gives you no control to put it back, and REST is the only way to restore it. Here the UI is the permissive surface and the docs are the strict ones.
The epic's own Child work items panel then shows the whole mixed set side by side — stories and sub-tasks in one flat list, with no visual hint that two of them arrived from a level that should not reach it.
The split: team-managed refuses the identical call
Here is the part I have not seen written down anywhere, and it is the reason this argument never resolves in a forum thread: the answer depends on which kind of project you are standing in. Two people can run the same test, get opposite results, and both be reporting honestly. It is the same shape as clearing the Done column, where the mechanism that works on a company-managed board does not exist on a team-managed one — a solution written for one project type is simply not about the other.
In a team-managed project, the same POST is refused:
Team-managed project
Result
Subtask, parent = Epic
400 — Please select valid parent issue.
Story, parent = Epic (control)
201 Created
Subtask, parent = Story (control)
201 Created
Story, parent = Story (control)
400 — Please select valid parent issue.
PUT an existing Subtask's parent to the Epic
400 — Issues with this Issue Type must be created in the same project as the parent.
6 rows × 2 columnsHeader row enabled
The controls matter as much here as the refusals did in the other direction: the sub-task type works fine in that project and the endpoint creates issues in it happily, so the 400 is the hierarchy validator talking and not a scheme or permission problem. I ran this on the site's existing team-managed project and then created a second team-managed project from scratch to check it was not a quirk of one board's configuration. Both refused, both with passing controls.
The UI agrees with its own API there. In the team-managed project, typing the epic's exact summary into a sub-task's Change parent dialog returns "No options" — while the same dialog in the company-managed project offered the epic on a partial match.
Atlassian's JQL reference points at the same boundary from another angle. The parentEpic clause is documented as "Only applicable for company-managed spaces", and describes itself as searching "work items and subtasks that are linked to the parent-level work type used for larger pieces of work". Atlassian's own JQL vocabulary assumes sub-tasks can be linked to an epic, and only in the project type where I measured it working.
What actually breaks
Nothing throws. That is the problem. What you get instead is a set of read surfaces that disagree about whether the sub-task exists under that epic:
Surface
Sees the sub-task under the epic?
GET /rest/api/3/issue/<epic>?fields=subtasks
Yes
JQL parent = <epic>
Yes
JQL parentEpic = <epic>
Yes
The epic's Child work items panel in the UI
Yes
JQL "Epic Link" = <epic> (legacy field)
No — only the standard children
GET /rest/agile/1.0/epic/<epic>/issue
No — only the standard children
7 rows × 2 columnsHeader row enabled
If your board tooling, your export or your dashboard is built on the Agile epic endpoint or the legacy Epic Link field, that work is invisible under its epic. If it is built on parent, it is visible. Both are defensible readings of "the epic's children" and they now return different sets from the same data. This is exactly the failure mode behind the community question about exporting a full Epic→Task→Subtask hierarchy with correct parent-child relations — an export walking one relationship gives you a tree that a second export walking the other relationship contradicts.
There is a second consequence that will find you during cleanup. An epic with a sub-task hanging off it is now, as far as the API is concerned, an issue with sub-tasks:
text
1DELETE /rest/api/3/issue/<epic>
2→ 400 The issue 'HIERP-6' has subtasks. You must specify the
3 'deleteSubtasks' parameter to delete this issue and all its subtasks.
45DELETE /rest/api/3/issue/<epic>?deleteSubtasks=true
6→ 204
So an epic you expected to delete cleanly refuses, and the flag that makes it succeed also deletes the orphaned sub-task. In a bulk cleanup script that reflexively retries with deleteSubtasks=true, that deletion is silent.
Finding them
Do not trust a "we don't have any" that you did not measure. Here is the query that works, and three ways to get a confidently wrong answer standing right next to it.
hierarchyLevel is a documented JQL field — the JQL fields reference gives it as Field Type Number, auto-complete Yes, supported operators = != > >= < <= IN NOT IN, with the note that "Currently, this field doesn't support custom hierarchy levels made in plans". It is also present in the site's own JQL autocomplete data (GET /rest/api/3/jql/autocompletedata returned 363 visible field names on my site and hierarchyLevel is one of them). It is worth knowing that it does not appear anywhere in GET /rest/api/3/field — I searched the whole payload for the string "hierarchy" and got zero hits — so if you build queries from the field API you will never discover it.
The detection is two steps, because JQL has no sub-queries. First list your epics:
jql
1issuetype = Epic AND project = ABC
Then feed those keys back into a second query:
jql
1hierarchyLevel = -1 AND parent in (ABC-1, ABC-2, ABC-3)
Anything that comes back is a sub-task whose parent is an epic. On a large site, chunk the epic keys — parent in (...) takes a list, and you will hit a query length limit before you hit a logical one.
Three traps in the same neighbourhood, all measured:
parent in subTaskIssueTypes() runs, returns rows, and every row is wrong. It looks like it should mean "items whose parent is a sub-task". It does not. subTaskIssueTypes() returns issue type ids, and the parent clause compares them against issue ids. On my site the sub-task type ids are 10006, 10016 and 10134; the query returned four issues, whose parents turned out to be issue id 10006 (a Work package) and issue id 10134 (a Bug). Four rows, four false positives, no error. A numeric collision between two unrelated id spaces is not something you will spot by reading the result.
parentEpic is not EMPTY returns nothing, on a site where parentEpic = <epic> returns six issues. Both is EMPTY and is not EMPTY came back with zero rows and HTTP 200. Atlassian documents IS and IS NOT as unsupported operators for parentEpic — but Jira does not reject the query, it silently answers it with an empty set. An empty result from an unsupported operator is indistinguishable from a clean instance, and if you are auditing for exactly this problem it will tell you that you do not have it.
A query run immediately after a parent edit can return the old parent. Mine did: right after re-parenting a sub-task back to its story, the detector still listed it under the epic. A re-run a minute later was clean. Parent changes made through PUT are not instantly visible to the search index, so an automation rule that edits a parent and then looks the item up by JQL in the same execution can act on stale data. Prefer the subtasks array or a direct re-fetch over a JQL round-trip immediately after a parent edit.
While I was checking whether Jira could prevent any of this natively, I pulled the platform's whole workflow-rule catalogue out of the Cloud swagger — curl -s https://developer.atlassian.com/cloud/jira/platform/swagger-v3.v3.json | grep -o 'system:[a-z0-9-]*' | sort -u returns 24 lines, of which one is a bare system: prefix, so 23 real rule keys. Exactly two mention the parent, system:parent-or-child-blocking-condition and system:parent-or-child-blocking-validator, and both are about the parent's or child's status, not its type or level. There is no native rule anywhere in that catalogue that can look at what a parent is. Transition-time validation that reasons about content rather than status is the gap our own CogniRunner sits in; I have not tested it against a parent-level check, so treat that as a direction rather than a recipe.
Fixing them
The repair is the same call that caused it, pointed somewhere sensible. PUT /rest/api/3/issue/<sub-task> with {"fields":{"parent":{"key":"<a level-0 item>"}}} returned 204 and the sub-task moved back under its story.
If the item should never have been a sub-task at all, do not reach for the same PUT with an issuetype in it — changing a sub-task into a Story that way returned 400 {"issuetype": "The issue type selected is invalid."}. POST /rest/api/3/bulk/issues/move does it, with the target expressed as a "<project>,<issueTypeId>" mapping key; mine returned 201, the queued task reported COMPLETE with one item and zero failures, and the read-back showed the issue as a Story. Note what else it did: the parent link was dropped to null. The conversion is not a re-parent, so budget a second call to put the item where it belongs.
Whether you should fix them is a genuine question and not a rhetorical one. Atlassian calls this expected behaviour, so a sub-task under an epic is not corrupt data — it is data that half your tooling reads and half does not. If everything you run is built on parent, you may reasonably leave them alone. If anything you run is built on Epic Link or the Agile epic endpoint, they are a slow leak in your reporting, and the leak grows every time somebody changes a parent.
Either repair is reversible in the narrow sense that one API call undoes it, but do not let that talk you into a bulk pass without a dry run. The type conversion in particular leaves the item parentless between the two calls, and if the second call fails you have turned a mis-levelled sub-task into an orphaned story that nothing rolls up.
What I did not test
Being precise about the edges is the difference between this being useful and being another confident forum answer.
Plan and edition. This was measured on a Free site. I have not run it on Standard, Premium or Enterprise, and Premium adds custom hierarchy levels above Epic, which is a different validator surface. I would expect the same result and I have not proved it.
Custom levels above Epic. Everything here is about the sub-task level against the default Epic level. Whether a sub-task can be parented to an Initiative at level 3 is a separate question — Atlassian's KB mentions "Epic/initiative", but I did not measure it.
Data Center. All of it is Jira Cloud. Both Atlassian articles I quote carry Cloud-only platform notices, and the hierarchy admin surface on Data Center is a different thing entirely.
Whether the team-managed refusal is permanent. It is what two team-managed projects did on 2026-08-25. It is not a documented guarantee, and I would not build on it staying true.
Anything below site admin. Every call and every click above was made by an account holding Jira administrator rights on that site. I did not test whether a project-level role sees the same picker options or gets the same responses.
The general rule survives all of this, by the way. Every standard-level skip I tried was refused, and JRACLOUD-89913 is still open with 80 votes and no resolution. I have no measurement of the Initiative-to-Epic case that member actually asked about — that needs the custom levels only Premium and Enterprise give you — so the honest answer there is still the open feature request rather than anything I ran. What I got wrong on that thread was stating the rule as a universal, and the level where it fails is the one most instances have the most of.
If you administer a company-managed project and you have never checked, the two-line query above takes a minute. Everything I have described here is something Jira will do without telling you.